Auto merge of #95958 - jhpratt:bump-stdarch, r=Dylan-DPC

Update stdarch

library/stdarch bcbe0106...d215afe9 (7):
  - Add the rdm target feature to the sqrdmlsh intrinsic. (rust-lang/stdarch#1285)
  - Remove use of `#[rustc_deprecated]`
  - Remove feature gates for stabilized features
  - Change remaining _undefined_ functions to zero-init
  - Use SPDX license format and update packed_simd crate link (rust-lang/stdarch#1297)
  - Fix broken links (rust-lang/stdarch#1294)
  - Import the asm macro in std_detect (rust-lang/stdarch#1290)
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 538bfc2..a7c23db 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -9,6 +9,8 @@
     test(attr(deny(warnings)))
 )]
 #![feature(box_patterns)]
+#![feature(const_default_impls)]
+#![feature(const_trait_impl)]
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(label_break_value)]
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 70dbda8..89a0857 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -128,14 +128,7 @@ fn encode(&self, s: &mut S) -> Result<(), S::Error> {
 
 impl<T> P<[T]> {
     pub const fn new() -> P<[T]> {
-        // HACK(eddyb) bypass the lack of a `const fn` to create an empty `Box<[T]>`
-        // (as trait methods, `default` in this case, can't be `const fn` yet).
-        P {
-            ptr: unsafe {
-                use std::ptr::NonNull;
-                std::mem::transmute(NonNull::<[T; 0]>::dangling() as NonNull<[T]>)
-            },
-        }
+        P { ptr: Box::default() }
     }
 
     #[inline(never)]
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index 8ce44ad..87fbb73 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -3,7 +3,7 @@
 use rustc_data_structures::{
     fingerprint::Fingerprint,
     fx::FxHashMap,
-    stable_hasher::{HashStable, NodeIdHashingMode, StableHasher},
+    stable_hasher::{HashStable, StableHasher},
 };
 use rustc_middle::{
     bug,
@@ -94,11 +94,7 @@ pub fn for_vtable_ty(
     pub fn generate_unique_id_string(self, tcx: TyCtxt<'tcx>) -> String {
         let mut hasher = StableHasher::new();
         let mut hcx = tcx.create_stable_hashing_context();
-        hcx.while_hashing_spans(false, |hcx| {
-            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                self.hash_stable(hcx, &mut hasher);
-            });
-        });
+        hcx.while_hashing_spans(false, |hcx| self.hash_stable(hcx, &mut hasher));
         hasher.finish::<Fingerprint>().to_hex()
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 369ca95..ae43464 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -19,7 +19,6 @@
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, ExistentialProjection, GeneratorSubsts, ParamEnv, Ty, TyCtxt};
-use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use smallvec::SmallVec;
 
@@ -704,11 +703,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
                 // but we get a deterministic, virtually unique value for the constant.
                 let hcx = &mut tcx.create_stable_hashing_context();
                 let mut hasher = StableHasher::new();
-                hcx.while_hashing_spans(false, |hcx| {
-                    hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                        ct.val().hash_stable(hcx, &mut hasher);
-                    });
-                });
+                hcx.while_hashing_spans(false, |hcx| ct.val().hash_stable(hcx, &mut hasher));
                 // Let's only emit 64 bits of the hash value. That should be plenty for
                 // avoiding collisions and will make the emitted type names shorter.
                 let hash: u64 = hasher.finish();
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 58a7f6d..01af958 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -3,15 +3,14 @@
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::interpret::Scalar;
-use rustc_middle::mir::traversal;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
-    AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPass, MirPhase, Operand,
-    PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator,
-    TerminatorKind, START_BLOCK,
+    traversal, AggregateKind, BasicBlock, BinOp, Body, BorrowKind, Local, Location, MirPass,
+    MirPhase, Operand, Place, PlaceElem, PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement,
+    StatementKind, Terminator, TerminatorKind, UnOp, START_BLOCK,
 };
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeFoldable};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::AlwaysLiveLocals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -36,6 +35,13 @@ pub struct Validator {
 
 impl<'tcx> MirPass<'tcx> for Validator {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
+        // terribly important that they pass the validator. However, I think other passes might
+        // still see them, in which case they might be surprised. It would probably be better if we
+        // didn't put this through the MIR pipeline at all.
+        if matches!(body.source.instance, InstanceDef::Intrinsic(..) | InstanceDef::Virtual(..)) {
+            return;
+        }
         let def_id = body.source.def_id();
         let param_env = tcx.param_env(def_id);
         let mir_phase = self.mir_phase;
@@ -240,6 +246,152 @@ fn visit_projection_elem(
         self.super_projection_elem(local, proj_base, elem, context, location);
     }
 
+    fn visit_place(&mut self, place: &Place<'tcx>, _: PlaceContext, _: Location) {
+        // Set off any `bug!`s in the type computation code
+        let _ = place.ty(&self.body.local_decls, self.tcx);
+    }
+
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        macro_rules! check_kinds {
+            ($t:expr, $text:literal, $($patterns:tt)*) => {
+                if !matches!(($t).kind(), $($patterns)*) {
+                    self.fail(location, format!($text, $t));
+                }
+            };
+        }
+        match rvalue {
+            Rvalue::Use(_) => {}
+            Rvalue::Aggregate(agg_kind, _) => {
+                let disallowed = match **agg_kind {
+                    AggregateKind::Array(..) => false,
+                    AggregateKind::Generator(..) => self.mir_phase >= MirPhase::GeneratorsLowered,
+                    _ => self.mir_phase >= MirPhase::Deaggregated,
+                };
+                if disallowed {
+                    self.fail(
+                        location,
+                        format!("{:?} have been lowered to field assignments", rvalue),
+                    )
+                }
+            }
+            Rvalue::Ref(_, BorrowKind::Shallow, _) => {
+                if self.mir_phase >= MirPhase::DropsLowered {
+                    self.fail(
+                        location,
+                        "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
+                    );
+                }
+            }
+            Rvalue::Len(p) => {
+                let pty = p.ty(&self.body.local_decls, self.tcx).ty;
+                check_kinds!(
+                    pty,
+                    "Cannot compute length of non-array type {:?}",
+                    ty::Array(..) | ty::Slice(..)
+                );
+            }
+            Rvalue::BinaryOp(op, vals) | Rvalue::CheckedBinaryOp(op, vals) => {
+                use BinOp::*;
+                let a = vals.0.ty(&self.body.local_decls, self.tcx);
+                let b = vals.1.ty(&self.body.local_decls, self.tcx);
+                match op {
+                    Offset => {
+                        check_kinds!(a, "Cannot offset non-pointer type {:?}", ty::RawPtr(..));
+                        if b != self.tcx.types.isize && b != self.tcx.types.usize {
+                            self.fail(location, format!("Cannot offset by non-isize type {:?}", b));
+                        }
+                    }
+                    Eq | Lt | Le | Ne | Ge | Gt => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot compare type {:?}",
+                                ty::Bool
+                                    | ty::Char
+                                    | ty::Int(..)
+                                    | ty::Uint(..)
+                                    | ty::Float(..)
+                                    | ty::RawPtr(..)
+                                    | ty::FnPtr(..)
+                            )
+                        }
+                        // None of the possible types have lifetimes, so we can just compare
+                        // directly
+                        if a != b {
+                            self.fail(
+                                location,
+                                format!("Cannot compare unequal types {:?} and {:?}", a, b),
+                            );
+                        }
+                    }
+                    Shl | Shr => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot shift non-integer type {:?}",
+                                ty::Uint(..) | ty::Int(..)
+                            )
+                        }
+                    }
+                    BitAnd | BitOr | BitXor => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot perform bitwise op on type {:?}",
+                                ty::Uint(..) | ty::Int(..) | ty::Bool
+                            )
+                        }
+                        if a != b {
+                            self.fail(
+                                location,
+                                format!(
+                                    "Cannot perform bitwise op on unequal types {:?} and {:?}",
+                                    a, b
+                                ),
+                            );
+                        }
+                    }
+                    Add | Sub | Mul | Div | Rem => {
+                        for x in [a, b] {
+                            check_kinds!(
+                                x,
+                                "Cannot perform op on type {:?}",
+                                ty::Uint(..) | ty::Int(..) | ty::Float(..)
+                            )
+                        }
+                        if a != b {
+                            self.fail(
+                                location,
+                                format!("Cannot perform op on unequal types {:?} and {:?}", a, b),
+                            );
+                        }
+                    }
+                }
+            }
+            Rvalue::UnaryOp(op, operand) => {
+                let a = operand.ty(&self.body.local_decls, self.tcx);
+                match op {
+                    UnOp::Neg => {
+                        check_kinds!(a, "Cannot negate type {:?}", ty::Int(..) | ty::Float(..))
+                    }
+                    UnOp::Not => {
+                        check_kinds!(
+                            a,
+                            "Cannot binary not type {:?}",
+                            ty::Int(..) | ty::Uint(..) | ty::Bool
+                        );
+                    }
+                }
+            }
+            Rvalue::ShallowInitBox(operand, _) => {
+                let a = operand.ty(&self.body.local_decls, self.tcx);
+                check_kinds!(a, "Cannot shallow init type {:?}", ty::RawPtr(..));
+            }
+            _ => {}
+        }
+        self.super_rvalue(rvalue, location);
+    }
+
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match &statement.kind {
             StatementKind::Assign(box (dest, rvalue)) => {
@@ -257,41 +409,16 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                         ),
                     );
                 }
-                match rvalue {
-                    // The sides of an assignment must not alias. Currently this just checks whether the places
-                    // are identical.
-                    Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) => {
-                        if dest == src {
-                            self.fail(
-                                location,
-                                "encountered `Assign` statement with overlapping memory",
-                            );
-                        }
+                // FIXME(JakobDegen): Check this for all rvalues, not just this one.
+                if let Rvalue::Use(Operand::Copy(src) | Operand::Move(src)) = rvalue {
+                    // The sides of an assignment must not alias. Currently this just checks whether
+                    // the places are identical.
+                    if dest == src {
+                        self.fail(
+                            location,
+                            "encountered `Assign` statement with overlapping memory",
+                        );
                     }
-                    Rvalue::Aggregate(agg_kind, _) => {
-                        let disallowed = match **agg_kind {
-                            AggregateKind::Array(..) => false,
-                            AggregateKind::Generator(..) => {
-                                self.mir_phase >= MirPhase::GeneratorsLowered
-                            }
-                            _ => self.mir_phase >= MirPhase::Deaggregated,
-                        };
-                        if disallowed {
-                            self.fail(
-                                location,
-                                format!("{:?} have been lowered to field assignments", rvalue),
-                            )
-                        }
-                    }
-                    Rvalue::Ref(_, BorrowKind::Shallow, _) => {
-                        if self.mir_phase >= MirPhase::DropsLowered {
-                            self.fail(
-                                location,
-                                "`Assign` statement with a `Shallow` borrow should have been removed after drop lowering phase",
-                            );
-                        }
-                    }
-                    _ => {}
                 }
             }
             StatementKind::AscribeUserType(..) => {
@@ -512,6 +639,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
             }
             TerminatorKind::Yield { resume, drop, .. } => {
+                if self.body.generator.is_none() {
+                    self.fail(location, "`Yield` cannot appear outside generator bodies");
+                }
                 if self.mir_phase >= MirPhase::GeneratorsLowered {
                     self.fail(location, "`Yield` should have been replaced by generator lowering");
                 }
@@ -551,6 +681,9 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 }
             }
             TerminatorKind::GeneratorDrop => {
+                if self.body.generator.is_none() {
+                    self.fail(location, "`GeneratorDrop` cannot appear outside generator bodies");
+                }
                 if self.mir_phase >= MirPhase::GeneratorsLowered {
                     self.fail(
                         location,
@@ -558,11 +691,19 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     );
                 }
             }
-            // Nothing to validate for these.
-            TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable => {}
+            TerminatorKind::Resume | TerminatorKind::Abort => {
+                let bb = location.block;
+                if !self.body.basic_blocks()[bb].is_cleanup {
+                    self.fail(location, "Cannot `Resume` or `Abort` from non-cleanup basic block")
+                }
+            }
+            TerminatorKind::Return => {
+                let bb = location.block;
+                if self.body.basic_blocks()[bb].is_cleanup {
+                    self.fail(location, "Cannot `Return` from cleanup basic block")
+                }
+            }
+            TerminatorKind::Unreachable => {}
         }
 
         self.super_terminator(terminator, location);
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index e8d81d4..85ad0f2 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -612,12 +612,6 @@ fn stable_hash_reduce<HCX, I, C, F>(
     }
 }
 
-#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
-pub enum NodeIdHashingMode {
-    Ignore,
-    HashDefPath,
-}
-
 /// Controls what data we do or not not hash.
 /// Whenever a `HashStable` implementation caches its
 /// result, it needs to include `HashingControls` as part
@@ -628,5 +622,4 @@ pub enum NodeIdHashingMode {
 #[derive(Clone, Hash, Eq, PartialEq, Debug)]
 pub struct HashingControls {
     pub hash_spans: bool,
-    pub node_id_hashing_mode: NodeIdHashingMode,
 }
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 88f3b54..b33e6b6 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -11,7 +11,7 @@
 use std::fmt;
 use std::fs;
 use std::io;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 use tracing::{instrument, trace};
 
 #[cfg(parallel_compiler)]
@@ -45,7 +45,7 @@ pub enum TranslationBundleError {
     /// Failed to add `FluentResource` to `FluentBundle`.
     AddResource(FluentError),
     /// `$sysroot/share/locale/$locale` does not exist.
-    MissingLocale(io::Error),
+    MissingLocale,
     /// Cannot read directory entries of `$sysroot/share/locale/$locale`.
     ReadLocalesDir(io::Error),
     /// Cannot read directory entry of `$sysroot/share/locale/$locale`.
@@ -62,9 +62,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 write!(f, "could not parse ftl file: {}", e)
             }
             TranslationBundleError::AddResource(e) => write!(f, "failed to add resource: {}", e),
-            TranslationBundleError::MissingLocale(e) => {
-                write!(f, "missing locale directory: {}", e)
-            }
+            TranslationBundleError::MissingLocale => write!(f, "missing locale directory"),
             TranslationBundleError::ReadLocalesDir(e) => {
                 write!(f, "could not read locales dir: {}", e)
             }
@@ -84,7 +82,7 @@ fn source(&self) -> Option<&(dyn Error + 'static)> {
             TranslationBundleError::ReadFtl(e) => Some(e),
             TranslationBundleError::ParseFtl(e) => Some(e),
             TranslationBundleError::AddResource(e) => Some(e),
-            TranslationBundleError::MissingLocale(e) => Some(e),
+            TranslationBundleError::MissingLocale => None,
             TranslationBundleError::ReadLocalesDir(e) => Some(e),
             TranslationBundleError::ReadLocalesDirEntry(e) => Some(e),
             TranslationBundleError::LocaleIsNotDir => None,
@@ -113,7 +111,8 @@ fn from(mut errs: Vec<FluentError>) -> Self {
 /// (overriding any conflicting messages).
 #[instrument(level = "trace")]
 pub fn fluent_bundle(
-    sysroot: &Path,
+    mut user_provided_sysroot: Option<PathBuf>,
+    mut sysroot_candidates: Vec<PathBuf>,
     requested_locale: Option<LanguageIdentifier>,
     additional_ftl_path: Option<&Path>,
     with_directionality_markers: bool,
@@ -140,33 +139,43 @@ pub fn fluent_bundle(
 
     // If the user requests the default locale then don't try to load anything.
     if !requested_fallback_locale && let Some(requested_locale) = requested_locale {
-        let mut sysroot = sysroot.to_path_buf();
-        sysroot.push("share");
-        sysroot.push("locale");
-        sysroot.push(requested_locale.to_string());
-        trace!(?sysroot);
+        let mut found_resources = false;
+        for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) {
+            sysroot.push("share");
+            sysroot.push("locale");
+            sysroot.push(requested_locale.to_string());
+            trace!(?sysroot);
 
-        let _ = sysroot.try_exists().map_err(TranslationBundleError::MissingLocale)?;
-
-        if !sysroot.is_dir() {
-            return Err(TranslationBundleError::LocaleIsNotDir);
-        }
-
-        for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
-            let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
-            let path = entry.path();
-            trace!(?path);
-            if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
+            if !sysroot.exists() {
                 trace!("skipping");
                 continue;
             }
 
-            let resource_str =
-                fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
-            let resource =
-                FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
-            trace!(?resource);
-            bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
+            if !sysroot.is_dir() {
+                return Err(TranslationBundleError::LocaleIsNotDir);
+            }
+
+            for entry in sysroot.read_dir().map_err(TranslationBundleError::ReadLocalesDir)? {
+                let entry = entry.map_err(TranslationBundleError::ReadLocalesDirEntry)?;
+                let path = entry.path();
+                trace!(?path);
+                if path.extension().and_then(|s| s.to_str()) != Some("ftl") {
+                    trace!("skipping");
+                    continue;
+                }
+
+                let resource_str =
+                    fs::read_to_string(path).map_err(TranslationBundleError::ReadFtl)?;
+                let resource =
+                    FluentResource::try_new(resource_str).map_err(TranslationBundleError::from)?;
+                trace!(?resource);
+                bundle.add_resource(resource).map_err(TranslationBundleError::from)?;
+                found_resources = true;
+            }
+        }
+
+        if !found_resources {
+            return Err(TranslationBundleError::MissingLocale);
         }
     }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ce243b4..b5f56d7 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -81,22 +81,12 @@
 use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::Span;
 
-use smallvec::{smallvec, SmallVec};
-
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lrc;
 use rustc_span::symbol::Ident;
 use std::borrow::Cow;
 use std::collections::hash_map::Entry::{Occupied, Vacant};
 
-// One element is enough to cover 95-99% of vectors for most benchmarks. Also, vectors longer than
-// one frequently have many elements, not just two or three.
-type NamedMatchVec = SmallVec<[NamedMatch; 1]>;
-
-// This type is used a lot. Make sure it doesn't unintentionally get bigger.
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(NamedMatchVec, 48);
-
 /// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
 /// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
 /// Notable differences to `mbe::TokenTree`:
@@ -221,7 +211,11 @@ struct MatcherPos {
     /// with one element per metavar decl in the matcher. Each element records token trees matched
     /// against the relevant metavar by the black box parser. An element will be a `MatchedSeq` if
     /// the corresponding metavar decl is within a sequence.
-    matches: Lrc<NamedMatchVec>,
+    ///
+    /// It is critical to performance that this is an `Lrc`, because it gets cloned frequently when
+    /// processing sequences. Mostly for sequence-ending possibilities that must be tried but end
+    /// up failing.
+    matches: Lrc<Vec<NamedMatch>>,
 }
 
 // This type is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -246,18 +240,12 @@ fn push_match(&mut self, metavar_idx: usize, seq_depth: usize, m: NamedMatch) {
                 let mut curr = &mut matches[metavar_idx];
                 for _ in 0..seq_depth - 1 {
                     match curr {
-                        MatchedSeq(seq) => {
-                            let seq = Lrc::make_mut(seq);
-                            curr = seq.last_mut().unwrap();
-                        }
+                        MatchedSeq(seq) => curr = seq.last_mut().unwrap(),
                         _ => unreachable!(),
                     }
                 }
                 match curr {
-                    MatchedSeq(seq) => {
-                        let seq = Lrc::make_mut(seq);
-                        seq.push(m);
-                    }
+                    MatchedSeq(seq) => seq.push(m),
                     _ => unreachable!(),
                 }
             }
@@ -350,7 +338,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
 /// ```
 #[derive(Debug, Clone)]
 crate enum NamedMatch {
-    MatchedSeq(Lrc<NamedMatchVec>),
+    MatchedSeq(Vec<NamedMatch>),
 
     // A metavar match of type `tt`.
     MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
@@ -388,7 +376,7 @@ pub struct TtParser {
 
     /// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
     /// that have no metavars.
-    empty_matches: Lrc<NamedMatchVec>,
+    empty_matches: Lrc<Vec<NamedMatch>>,
 }
 
 impl TtParser {
@@ -398,7 +386,7 @@ pub(super) fn new(macro_name: Ident) -> TtParser {
             cur_mps: vec![],
             next_mps: vec![],
             bb_mps: vec![],
-            empty_matches: Lrc::new(smallvec![]),
+            empty_matches: Lrc::new(vec![]),
         }
     }
 
@@ -452,11 +440,7 @@ fn parse_tt_inner(
                 } => {
                     // Install an empty vec for each metavar within the sequence.
                     for metavar_idx in next_metavar..next_metavar + num_metavar_decls {
-                        mp.push_match(
-                            metavar_idx,
-                            seq_depth,
-                            MatchedSeq(self.empty_matches.clone()),
-                        );
+                        mp.push_match(metavar_idx, seq_depth, MatchedSeq(vec![]));
                     }
 
                     if op == KleeneOp::ZeroOrMore || op == KleeneOp::ZeroOrOne {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 31dae6a..f5c7186 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -439,7 +439,8 @@ pub fn compile_declarative_macro(
     let argument_gram = mbe::macro_parser::compute_locs(&sess.parse_sess, &argument_gram);
 
     let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
-    let mut tt_parser = TtParser::new(def.ident);
+    let mut tt_parser =
+        TtParser::new(Ident::with_dummy_span(if macro_rules { kw::MacroRules } else { kw::Macro }));
     let argument_map = match tt_parser.parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
         Success(m) => m,
         Failure(token, msg) => {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 7c53f83..e588385 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -310,7 +310,7 @@ pub struct BuiltinAttribute {
 
     // Crate properties:
     ungated!(crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing),
-    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), FutureWarnFollowing),
+    ungated!(crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk),
     // crate_id is deprecated
     ungated!(crate_id, CrateLevel, template!(NameValueStr: "ignored"), FutureWarnFollowing),
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 1511807..ff8b13d 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -17,7 +17,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable_Generic;
 use rustc_span::hygiene::MacroKind;
-use rustc_span::source_map::Spanned;
+use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -523,6 +523,40 @@ pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
             })
             .map(|sp| sp.shrink_to_hi())
     }
+
+    /// Returns the span of `:` after a generic parameter.
+    ///
+    /// For example:
+    ///
+    /// ```text
+    /// fn a<T:>()
+    ///       ^
+    ///       |      here
+    ///       here   |
+    ///              v
+    /// fn b<T       :>()
+    ///
+    /// fn c<T
+    ///
+    /// :>()
+    /// ^
+    /// |
+    /// here
+    /// ```
+    pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option<Span> {
+        let sp = source_map
+            .span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':')
+            .ok()?;
+
+        let snippet = source_map.span_to_snippet(sp).ok()?;
+        let offset = snippet.find(':')?;
+
+        let colon_sp = sp
+            .with_lo(BytePos(sp.lo().0 + offset as u32))
+            .with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32));
+
+        Some(colon_sp)
+    }
 }
 
 #[derive(Default)]
@@ -1265,7 +1299,7 @@ pub struct BodyId {
 ///
 /// All bodies have an **owner**, which can be accessed via the HIR
 /// map using `body_owner_def_id()`.
-#[derive(Debug)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Body<'hir> {
     pub params: &'hir [Param<'hir>],
     pub value: Expr<'hir>,
@@ -2025,7 +2059,7 @@ pub struct FnSig<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
 pub struct TraitItemId {
     pub def_id: LocalDefId,
 }
@@ -2042,7 +2076,7 @@ pub fn hir_id(&self) -> HirId {
 /// possibly including a default implementation. A trait item is
 /// either required (meaning it doesn't have an implementation, just a
 /// signature) or provided (meaning it has a default implementation).
-#[derive(Debug)]
+#[derive(Debug, HashStable_Generic)]
 pub struct TraitItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
@@ -2088,7 +2122,7 @@ pub enum TraitItemKind<'hir> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
 pub struct ImplItemId {
     pub def_id: LocalDefId,
 }
@@ -2102,7 +2136,7 @@ pub fn hir_id(&self) -> HirId {
 }
 
 /// Represents anything within an `impl` block.
-#[derive(Debug)]
+#[derive(Debug, HashStable_Generic)]
 pub struct ImplItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
@@ -2603,7 +2637,7 @@ pub struct PolyTraitRef<'hir> {
 
 pub type Visibility<'hir> = Spanned<VisibilityKind<'hir>>;
 
-#[derive(Copy, Clone, Debug)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum VisibilityKind<'hir> {
     Public,
     Crate(CrateSugar),
@@ -2679,7 +2713,7 @@ pub fn ctor_hir_id(&self) -> Option<HirId> {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, Hash)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, Hash, HashStable_Generic)]
 pub struct ItemId {
     pub def_id: LocalDefId,
 }
@@ -2695,7 +2729,7 @@ pub fn hir_id(&self) -> HirId {
 /// An item
 ///
 /// The name might be a dummy name in case of anonymous items
-#[derive(Debug)]
+#[derive(Debug, HashStable_Generic)]
 pub struct Item<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
@@ -2926,7 +2960,7 @@ pub enum AssocItemKind {
 // The bodies for items are stored "out of line", in a separate
 // hashmap in the `Crate`. Here we just record the hir-id of the item
 // so it can fetched later.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
 pub struct ForeignItemId {
     pub def_id: LocalDefId,
 }
@@ -2952,7 +2986,7 @@ pub struct ForeignItemRef {
     pub span: Span,
 }
 
-#[derive(Debug)]
+#[derive(Debug, HashStable_Generic)]
 pub struct ForeignItem<'hir> {
     pub ident: Ident,
     pub kind: ForeignItemKind<'hir>,
@@ -2994,7 +3028,7 @@ pub struct Upvar {
 // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
 // has length > 0 if the trait is found through an chain of imports, starting with the
 // import/use statement in the scope where the trait is used.
-#[derive(Encodable, Decodable, Clone, Debug)]
+#[derive(Encodable, Decodable, Clone, Debug, HashStable_Generic)]
 pub struct TraitCandidate {
     pub def_id: DefId,
     pub import_ids: SmallVec<[LocalDefId; 1]>,
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index f23e3ce..3b5e4dc 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -12,7 +12,7 @@
 /// incremental compilation where we have to persist things through changes to
 /// the code base.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic)]
 #[rustc_pass_by_value]
 pub struct HirId {
     pub owner: LocalDefId,
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 61f0344..8ccd59e 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,8 +1,8 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 
 use crate::hir::{
-    AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
-    ItemId, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
+    AttributeMap, BodyId, Crate, Expr, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
+    Ty,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 use rustc_span::def_id::DefPathHash;
@@ -13,14 +13,9 @@
 pub trait HashStableContext:
     rustc_ast::HashStableContext + rustc_target::HashStableContext
 {
-    fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher);
     fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher);
-    fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher);
     fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher);
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
-    fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
-    fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F);
-    fn hash_hir_trait_candidate(&mut self, _: &TraitCandidate, hasher: &mut StableHasher);
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@@ -88,12 +83,6 @@ fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HirId {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_hir_id(*self, hasher)
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for BodyId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         hcx.hash_body_id(*self, hasher)
@@ -107,30 +96,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
 // want to pick up on a reference changing its target, so we hash the NodeIds
 // in "DefPath Mode".
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ItemId {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id(), hasher)
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ForeignItemId {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id(), hasher)
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItemId {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id(), hasher)
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItemId {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_reference_to_item(self.hir_id(), hasher)
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         hcx.hash_hir_expr(self, hasher)
@@ -143,65 +108,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for VisibilityKind<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_hir_visibility_kind(self, hasher)
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitItem<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let TraitItem { def_id: _, ident, ref generics, ref kind, span } = *self;
-
-        hcx.hash_hir_item_like(|hcx| {
-            ident.name.hash_stable(hcx, hasher);
-            generics.hash_stable(hcx, hasher);
-            kind.hash_stable(hcx, hasher);
-            span.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span } = *self;
-
-        hcx.hash_hir_item_like(|hcx| {
-            ident.name.hash_stable(hcx, hasher);
-            vis.hash_stable(hcx, hasher);
-            generics.hash_stable(hcx, hasher);
-            kind.hash_stable(hcx, hasher);
-            span.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ForeignItem<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let ForeignItem { def_id: _, ident, ref kind, span, ref vis } = *self;
-
-        hcx.hash_hir_item_like(|hcx| {
-            ident.name.hash_stable(hcx, hasher);
-            kind.hash_stable(hcx, hasher);
-            span.hash_stable(hcx, hasher);
-            vis.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Item<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let Item { ident, def_id: _, ref kind, ref vis, span } = *self;
-
-        hcx.hash_hir_item_like(|hcx| {
-            ident.name.hash_stable(hcx, hasher);
-            kind.hash_stable(hcx, hasher);
-            vis.hash_stable(hcx, hasher);
-            span.hash_stable(hcx, hasher);
-        });
-    }
-}
-
 impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'tcx> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // We ignore the `nodes` and `bodies` fields since these refer to information included in
@@ -235,9 +141,3 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         hir_hash.hash_stable(hcx, hasher)
     }
 }
-
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for TraitCandidate {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_hir_trait_candidate(self, hasher)
-    }
-}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index a357032..fe75ee8 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -44,6 +44,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
     let sess = build_session(
         sessopts,
         None,
+        None,
         registry,
         DiagnosticOutput::Default,
         Default::default(),
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 592cf60..3fa8017 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -83,9 +83,23 @@ pub fn create_session(
     // target_override is documented to be called before init(), so this is okay
     let target_override = codegen_backend.target_override(&sopts);
 
+    let bundle = match rustc_errors::fluent_bundle(
+        sopts.maybe_sysroot.clone(),
+        sysroot_candidates(),
+        sopts.debugging_opts.translate_lang.clone(),
+        sopts.debugging_opts.translate_additional_ftl.as_deref(),
+        sopts.debugging_opts.translate_directionality_markers,
+    ) {
+        Ok(bundle) => bundle,
+        Err(e) => {
+            early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}"));
+        }
+    };
+
     let mut sess = session::build_session(
         sopts,
         input_path,
+        bundle,
         descriptions,
         diagnostic_output,
         lint_caps,
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 7030fd5..71f21dc 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -995,6 +995,13 @@
         break;
       }
     }
+  } else {
+    // We're not building any of the default pipelines but we still want to
+    // add the verifier, instrumentation, etc passes if they were requested
+    for (const auto &C : PipelineStartEPCallbacks)
+      C(MPM, OptLevel);
+    for (const auto &C : OptimizerLastEPCallbacks)
+      C(MPM, OptLevel);
   }
 
   if (ExtraPassesLen) {
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 06658aa..aebd293 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -5,7 +5,9 @@
 #![feature(nll)]
 #![feature(once_cell)]
 #![feature(proc_macro_internals)]
+#![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
+#![feature(slice_as_chunks)]
 #![feature(try_blocks)]
 #![feature(never_type)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 3402acc..3933a0d 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -292,6 +292,18 @@ fn decode_query(
     ) -> T;
 }
 
+impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for T {
+    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, _: impl FnOnce() -> !) -> T {
+        self
+    }
+}
+
+impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<T> {
+    fn decode_query(self, _: CrateMetadataRef<'a>, _: TyCtxt<'tcx>, err: impl FnOnce() -> !) -> T {
+        if let Some(l) = self { l } else { err() }
+    }
+}
+
 impl<'a, 'tcx, T> LazyQueryDecodable<'a, 'tcx, T> for Option<Lazy<T>>
 where
     T: Decodable<DecodeContext<'a, 'tcx>>,
@@ -376,6 +388,17 @@ fn decode_query(
     }
 }
 
+impl<'a, 'tcx> LazyQueryDecodable<'a, 'tcx, Option<DefId>> for Option<RawDefId> {
+    fn decode_query(
+        self,
+        cdata: CrateMetadataRef<'a>,
+        _: TyCtxt<'tcx>,
+        _: impl FnOnce() -> !,
+    ) -> Option<DefId> {
+        self.map(|raw_def_id| raw_def_id.decode(cdata))
+    }
+}
+
 impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
     #[inline]
     fn tcx(&self) -> TyCtxt<'tcx> {
@@ -394,8 +417,9 @@ pub fn cdata(&self) -> CrateMetadataRef<'a> {
         self.cdata.unwrap()
     }
 
+    #[inline]
     fn map_encoded_cnum_to_current(&self, cnum: CrateNum) -> CrateNum {
-        if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
+        self.cdata().map_encoded_cnum_to_current(cnum)
     }
 
     fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
@@ -706,8 +730,7 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
     }
 }
 
-impl<'a, 'tcx, I: Idx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
-    for Lazy<Table<I, T>>
+impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -844,6 +867,11 @@ fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
         self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
     }
 
+    #[inline]
+    pub(super) fn map_encoded_cnum_to_current(self, cnum: CrateNum) -> CrateNum {
+        if cnum == LOCAL_CRATE { self.cnum } else { self.cnum_map[cnum] }
+    }
+
     fn kind(self, item_id: DefIndex) -> EntryKind {
         self.maybe_kind(item_id).unwrap_or_else(|| {
             bug!(
@@ -856,16 +884,14 @@ fn kind(self, item_id: DefIndex) -> EntryKind {
     }
 
     fn def_kind(self, item_id: DefIndex) -> DefKind {
-        self.root.tables.opt_def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(
-            || {
-                bug!(
-                    "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
-                    item_id,
-                    self.root.name,
-                    self.cnum,
-                )
-            },
-        )
+        self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| {
+            bug!(
+                "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
+                item_id,
+                self.root.name,
+                self.cnum,
+            )
+        })
     }
 
     fn get_span(self, index: DefIndex, sess: &Session) -> Span {
@@ -1449,9 +1475,9 @@ fn def_path_hash_unlocked(
         index: DefIndex,
         def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
     ) -> DefPathHash {
-        *def_path_hashes.entry(index).or_insert_with(|| {
-            self.root.tables.def_path_hashes.get(self, index).unwrap().decode(self)
-        })
+        *def_path_hashes
+            .entry(index)
+            .or_insert_with(|| self.root.tables.def_path_hashes.get(self, index).unwrap())
     }
 
     #[inline]
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 6c758b8..e967750 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -147,8 +147,7 @@ fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
     }
 }
 
-impl<'a, 'tcx, I: Idx, T: Encodable<EncodeContext<'a, 'tcx>>> Encodable<EncodeContext<'a, 'tcx>>
-    for Lazy<Table<I, T>>
+impl<'a, 'tcx, I: Idx, T> Encodable<EncodeContext<'a, 'tcx>> for Lazy<Table<I, T>>
 where
     Option<T>: FixedSizeEncoding,
 {
@@ -461,16 +460,15 @@ fn encode_def_path_table(&mut self) {
                 .chain(self.tcx.resolutions(()).proc_macros.iter().map(|p| p.local_def_index))
             {
                 let def_key = self.lazy(table.def_key(def_index));
-                let def_path_hash = self.lazy(table.def_path_hash(def_index));
+                let def_path_hash = table.def_path_hash(def_index);
                 self.tables.def_keys.set(def_index, def_key);
                 self.tables.def_path_hashes.set(def_index, def_path_hash);
             }
         } else {
             for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() {
                 let def_key = self.lazy(def_key);
-                let def_path_hash = self.lazy(def_path_hash);
                 self.tables.def_keys.set(def_index, def_key);
-                self.tables.def_path_hashes.set(def_index, def_path_hash);
+                self.tables.def_path_hashes.set(def_index, *def_path_hash);
             }
         }
     }
@@ -988,7 +986,7 @@ fn encode_def_ids(&mut self) {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
             let Some(def_kind) = def_kind else { continue };
-            record!(self.tables.opt_def_kind[def_id] <- def_kind);
+            self.tables.opt_def_kind.set(def_id.index, def_kind);
             record!(self.tables.def_span[def_id] <- tcx.def_span(def_id));
             record!(self.tables.attributes[def_id] <- tcx.get_attrs(def_id));
             record!(self.tables.expn_that_defined[def_id] <- self.tcx.expn_that_defined(def_id));
@@ -1048,7 +1046,7 @@ fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx)
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         record!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
             assert!(f.did.is_local());
             f.did.index
@@ -1078,7 +1076,7 @@ fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx)
         };
 
         record!(self.tables.kind[def_id] <- EntryKind::Variant(self.lazy(data)));
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1157,7 +1155,7 @@ fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>, def_id: DefId) {
         };
 
         record!(self.tables.repr_options[def_id] <- adt_def.repr());
-        record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+        self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
         record!(self.tables.kind[def_id] <- EntryKind::Struct(self.lazy(data)));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
@@ -1207,8 +1205,8 @@ fn encode_info_for_trait_item(&mut self, def_id: DefId) {
                         record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body))
                     }
                 };
-                record!(self.tables.asyncness[def_id] <- m_sig.header.asyncness);
-                record!(self.tables.impl_constness[def_id] <- hir::Constness::NotConst);
+                self.tables.asyncness.set(def_id.index, m_sig.header.asyncness);
+                self.tables.impl_constness.set(def_id.index, hir::Constness::NotConst);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: trait_item.fn_has_self_parameter,
@@ -1265,7 +1263,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
             }
             ty::AssocKind::Fn => {
                 let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
-                record!(self.tables.asyncness[def_id] <- sig.header.asyncness);
+                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
                 // Can be inside `impl const Trait`, so using sig.header.constness is not reliable
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
@@ -1273,7 +1271,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
                 } else {
                     hir::Constness::NotConst
                 };
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::AssocFn(self.lazy(AssocFnData {
                     container,
                     has_self: impl_item.fn_has_self_parameter,
@@ -1286,7 +1284,7 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         self.encode_ident_span(def_id, impl_item.ident(self.tcx));
         self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
-            record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+            self.tables.trait_item_def_id.set(def_id.index, trait_item_def_id.into());
         }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
@@ -1394,9 +1392,9 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 EntryKind::Const
             }
             hir::ItemKind::Fn(ref sig, .., body) => {
-                record!(self.tables.asyncness[def_id] <- sig.header.asyncness);
+                self.tables.asyncness.set(def_id.index, sig.header.asyncness);
                 record!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
-                record!(self.tables.impl_constness[def_id] <- sig.header.constness);
+                self.tables.impl_constness.set(def_id.index, sig.header.constness);
                 EntryKind::Fn
             }
             hir::ItemKind::Macro(ref macro_def, _) => {
@@ -1420,7 +1418,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Struct(ref struct_def, _) => {
                 let adt_def = self.tcx.adt_def(def_id);
                 record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                record!(self.tables.impl_constness[def_id] <- hir::Constness::Const);
+                self.tables.impl_constness.set(def_id.index, hir::Constness::Const);
 
                 // Encode def_ids for each field and method
                 // for methods, write all the stuff get_trait_method
@@ -1450,15 +1448,15 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 }))
             }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
-                record!(self.tables.impl_defaultness[def_id] <- defaultness);
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_defaultness.set(def_id.index, defaultness);
+                self.tables.impl_constness.set(def_id.index, constness);
 
                 let trait_ref = self.tcx.impl_trait_ref(def_id);
                 if let Some(trait_ref) = trait_ref {
                     let trait_def = self.tcx.trait_def(trait_ref.def_id);
                     if let Some(mut an) = trait_def.ancestors(self.tcx, def_id).ok() {
                         if let Some(specialization_graph::Node::Impl(parent)) = an.nth(1) {
-                            record!(self.tables.impl_parent[def_id] <- parent);
+                            self.tables.impl_parent.set(def_id.index, parent.into());
                         }
                     }
 
@@ -1472,7 +1470,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                 }
 
                 let polarity = self.tcx.impl_polarity(def_id);
-                record!(self.tables.impl_polarity[def_id] <- polarity);
+                self.tables.impl_polarity.set(def_id.index, polarity);
 
                 EntryKind::Impl
             }
@@ -1644,7 +1642,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 self.tables.proc_macro_quoted_spans.set(i, span);
             }
 
-            record!(self.tables.opt_def_kind[LOCAL_CRATE.as_def_id()] <- DefKind::Mod);
+            self.tables.opt_def_kind.set(LOCAL_CRATE.as_def_id().index, DefKind::Mod);
             record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id()));
             record!(self.tables.attributes[LOCAL_CRATE.as_def_id()] <- tcx.get_attrs(LOCAL_CRATE.as_def_id()));
             record!(self.tables.visibility[LOCAL_CRATE.as_def_id()] <- tcx.visibility(LOCAL_CRATE.as_def_id()));
@@ -1685,7 +1683,7 @@ fn encode_proc_macros(&mut self) -> Option<ProcMacroData> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                record!(self.tables.opt_def_kind[def_id] <- DefKind::Macro(macro_kind));
+                self.tables.opt_def_kind.set(def_id.index, DefKind::Macro(macro_kind));
                 record!(self.tables.kind[def_id] <- EntryKind::ProcMacro(macro_kind));
                 record!(self.tables.attributes[def_id] <- attrs);
                 record!(self.tables.def_keys[def_id] <- def_key);
@@ -1886,14 +1884,14 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
 
         match nitem.kind {
             hir::ForeignItemKind::Fn(_, ref names, _) => {
-                record!(self.tables.asyncness[def_id] <- hir::IsAsync::NotAsync);
+                self.tables.asyncness.set(def_id.index, hir::IsAsync::NotAsync);
                 record!(self.tables.fn_arg_names[def_id] <- *names);
                 let constness = if self.tcx.is_const_fn_raw(def_id) {
                     hir::Constness::Const
                 } else {
                     hir::Constness::NotConst
                 };
-                record!(self.tables.impl_constness[def_id] <- constness);
+                self.tables.impl_constness.set(def_id.index, constness);
                 record!(self.tables.kind[def_id] <- EntryKind::ForeignFn);
             }
             hir::ForeignItemKind::Static(..) => {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 15e8693..43ccfc6 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,3 +1,4 @@
+use crate::creader::CrateMetadataRef;
 use decoder::Metadata;
 use def_path_hash_map::DefPathHashMapRef;
 use table::{Table, TableBuilder};
@@ -8,7 +9,7 @@
 use rustc_data_structures::sync::MetadataRef;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, DefIndex, DefPathHash, StableCrateId};
+use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
@@ -237,6 +238,29 @@ macro_rules! Lazy {
     symbol_mangling_version: SymbolManglingVersion,
 }
 
+/// On-disk representation of `DefId`.
+/// This creates a type-safe way to enforce that we remap the CrateNum between the on-disk
+/// representation and the compilation session.
+#[derive(Copy, Clone)]
+crate struct RawDefId {
+    krate: u32,
+    index: u32,
+}
+
+impl Into<RawDefId> for DefId {
+    fn into(self) -> RawDefId {
+        RawDefId { krate: self.krate.as_u32(), index: self.index.as_u32() }
+    }
+}
+
+impl RawDefId {
+    fn decode(self, cdata: CrateMetadataRef<'_>) -> DefId {
+        let krate = CrateNum::from_u32(self.krate);
+        let krate = cdata.map_encoded_cnum_to_current(krate);
+        DefId { krate, index: DefIndex::from_u32(self.index) }
+    }
+}
+
 #[derive(Encodable, Decodable)]
 crate struct CrateDep {
     pub name: Symbol,
@@ -286,7 +310,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     attributes: Table<DefIndex, Lazy<[ast::Attribute]>>,
     children: Table<DefIndex, Lazy<[DefIndex]>>,
 
-    opt_def_kind: Table<DefIndex, Lazy<DefKind>>,
+    opt_def_kind: Table<DefIndex, DefKind>,
     visibility: Table<DefIndex, Lazy<ty::Visibility>>,
     def_span: Table<DefIndex, Lazy<Span>>,
     def_ident_span: Table<DefIndex, Lazy<Span>>,
@@ -309,20 +333,20 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
     promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
     thir_abstract_const: Table<DefIndex, Lazy!(&'tcx [thir::abstract_const::Node<'tcx>])>,
-    impl_parent: Table<DefIndex, Lazy!(DefId)>,
-    impl_polarity: Table<DefIndex, Lazy!(ty::ImplPolarity)>,
-    impl_constness: Table<DefIndex, Lazy!(hir::Constness)>,
-    impl_defaultness: Table<DefIndex, Lazy!(hir::Defaultness)>,
+    impl_parent: Table<DefIndex, RawDefId>,
+    impl_polarity: Table<DefIndex, ty::ImplPolarity>,
+    impl_constness: Table<DefIndex, hir::Constness>,
+    impl_defaultness: Table<DefIndex, hir::Defaultness>,
     // FIXME(eddyb) perhaps compute this on the fly if cheap enough?
     coerce_unsized_info: Table<DefIndex, Lazy!(ty::adjustment::CoerceUnsizedInfo)>,
     mir_const_qualif: Table<DefIndex, Lazy!(mir::ConstQualifs)>,
     rendered_const: Table<DefIndex, Lazy!(String)>,
-    asyncness: Table<DefIndex, Lazy!(hir::IsAsync)>,
+    asyncness: Table<DefIndex, hir::IsAsync>,
     fn_arg_names: Table<DefIndex, Lazy!([Ident])>,
     generator_kind: Table<DefIndex, Lazy!(hir::GeneratorKind)>,
     trait_def: Table<DefIndex, Lazy!(ty::TraitDef)>,
 
-    trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
+    trait_item_def_id: Table<DefIndex, RawDefId>,
     inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
     expn_that_defined: Table<DefIndex, Lazy<ExpnId>>,
     unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
@@ -332,7 +356,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     // `DefPathTable` up front, since we may only ever use a few
     // definitions from any given crate.
     def_keys: Table<DefIndex, Lazy<DefKey>>,
-    def_path_hashes: Table<DefIndex, Lazy<DefPathHash>>,
+    def_path_hashes: Table<DefIndex, DefPathHash>,
     proc_macro_quoted_spans: Table<usize, Lazy<Span>>,
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 265ca5a..7a23cba 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -1,8 +1,11 @@
 use crate::rmeta::*;
 
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_hir::def::{CtorKind, CtorOf};
 use rustc_index::vec::Idx;
 use rustc_serialize::opaque::Encoder;
 use rustc_serialize::Encoder as _;
+use rustc_span::hygiene::MacroKind;
 use std::convert::TryInto;
 use std::marker::PhantomData;
 use std::num::NonZeroUsize;
@@ -13,66 +16,173 @@
 /// Unchecked invariant: `Self::default()` should encode as `[0; BYTE_LEN]`,
 /// but this has no impact on safety.
 pub(super) trait FixedSizeEncoding: Default {
-    const BYTE_LEN: usize;
+    /// This should be `[u8; BYTE_LEN]`;
+    type ByteArray;
 
-    // FIXME(eddyb) convert to and from `[u8; Self::BYTE_LEN]` instead,
-    // once that starts being allowed by the compiler (i.e. lazy normalization).
-    fn from_bytes(b: &[u8]) -> Self;
-    fn write_to_bytes(self, b: &mut [u8]);
-
-    // FIXME(eddyb) make these generic functions, or at least defaults here.
-    // (same problem as above, needs `[u8; Self::BYTE_LEN]`)
-    // For now, a macro (`fixed_size_encoding_byte_len_and_defaults`) is used.
-
-    /// Read a `Self` value (encoded as `Self::BYTE_LEN` bytes),
-    /// from `&b[i * Self::BYTE_LEN..]`, returning `None` if `i`
-    /// is not in bounds, or `Some(Self::from_bytes(...))` otherwise.
-    fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self>;
-    /// Write a `Self` value (encoded as `Self::BYTE_LEN` bytes),
-    /// at `&mut b[i * Self::BYTE_LEN..]`, using `Self::write_to_bytes`.
-    fn write_to_bytes_at(self, b: &mut [u8], i: usize);
-}
-
-// HACK(eddyb) this shouldn't be needed (see comments on the methods above).
-macro_rules! fixed_size_encoding_byte_len_and_defaults {
-    ($byte_len:expr) => {
-        const BYTE_LEN: usize = $byte_len;
-        fn maybe_read_from_bytes_at(b: &[u8], i: usize) -> Option<Self> {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // but slicing `[u8]` with `i * N..` is optimized worse, due to the
-            // possibility of `i * N` overflowing, than indexing `[[u8; N]]`.
-            let b = unsafe {
-                std::slice::from_raw_parts(b.as_ptr() as *const [u8; BYTE_LEN], b.len() / BYTE_LEN)
-            };
-            b.get(i).map(|b| FixedSizeEncoding::from_bytes(b))
-        }
-        fn write_to_bytes_at(self, b: &mut [u8], i: usize) {
-            const BYTE_LEN: usize = $byte_len;
-            // HACK(eddyb) ideally this would be done with fully safe code,
-            // see similar comment in `read_from_bytes_at` for why it can't yet.
-            let b = unsafe {
-                std::slice::from_raw_parts_mut(
-                    b.as_mut_ptr() as *mut [u8; BYTE_LEN],
-                    b.len() / BYTE_LEN,
-                )
-            };
-            self.write_to_bytes(&mut b[i]);
-        }
-    };
+    fn from_bytes(b: &Self::ByteArray) -> Self;
+    fn write_to_bytes(self, b: &mut Self::ByteArray);
 }
 
 impl FixedSizeEncoding for u32 {
-    fixed_size_encoding_byte_len_and_defaults!(4);
+    type ByteArray = [u8; 4];
 
-    fn from_bytes(b: &[u8]) -> Self {
-        let mut bytes = [0; Self::BYTE_LEN];
-        bytes.copy_from_slice(&b[..Self::BYTE_LEN]);
-        Self::from_le_bytes(bytes)
+    #[inline]
+    fn from_bytes(b: &[u8; 4]) -> Self {
+        Self::from_le_bytes(*b)
     }
 
-    fn write_to_bytes(self, b: &mut [u8]) {
-        b[..Self::BYTE_LEN].copy_from_slice(&self.to_le_bytes());
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 4]) {
+        *b = self.to_le_bytes();
+    }
+}
+
+macro_rules! fixed_size_enum {
+    ($ty:ty { $(($($pat:tt)*))* }) => {
+        impl FixedSizeEncoding for Option<$ty> {
+            type ByteArray = [u8;1];
+
+            #[inline]
+            fn from_bytes(b: &[u8;1]) -> Self {
+                use $ty::*;
+                if b[0] == 0 {
+                    return None;
+                }
+                match b[0] - 1 {
+                    $(${index()} => Some($($pat)*),)*
+                    _ => panic!("Unexpected ImplPolarity code: {:?}", b[0]),
+                }
+            }
+
+            #[inline]
+            fn write_to_bytes(self, b: &mut [u8;1]) {
+                use $ty::*;
+                b[0] = match self {
+                    None => 0,
+                    $(Some($($pat)*) => 1 + ${index()},)*
+                }
+            }
+        }
+    }
+}
+
+fixed_size_enum! {
+    DefKind {
+        ( Mod                                      )
+        ( Struct                                   )
+        ( Union                                    )
+        ( Enum                                     )
+        ( Variant                                  )
+        ( Trait                                    )
+        ( TyAlias                                  )
+        ( ForeignTy                                )
+        ( TraitAlias                               )
+        ( AssocTy                                  )
+        ( TyParam                                  )
+        ( Fn                                       )
+        ( Const                                    )
+        ( ConstParam                               )
+        ( AssocFn                                  )
+        ( AssocConst                               )
+        ( ExternCrate                              )
+        ( Use                                      )
+        ( ForeignMod                               )
+        ( AnonConst                                )
+        ( InlineConst                              )
+        ( OpaqueTy                                 )
+        ( Field                                    )
+        ( LifetimeParam                            )
+        ( GlobalAsm                                )
+        ( Impl                                     )
+        ( Closure                                  )
+        ( Generator                                )
+        ( Static(ast::Mutability::Not)             )
+        ( Static(ast::Mutability::Mut)             )
+        ( Ctor(CtorOf::Struct, CtorKind::Fn)       )
+        ( Ctor(CtorOf::Struct, CtorKind::Const)    )
+        ( Ctor(CtorOf::Struct, CtorKind::Fictive)  )
+        ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
+        ( Ctor(CtorOf::Variant, CtorKind::Const)   )
+        ( Ctor(CtorOf::Variant, CtorKind::Fictive) )
+        ( Macro(MacroKind::Bang)                   )
+        ( Macro(MacroKind::Attr)                   )
+        ( Macro(MacroKind::Derive)                 )
+    }
+}
+
+fixed_size_enum! {
+    ty::ImplPolarity {
+        ( Positive    )
+        ( Negative    )
+        ( Reservation )
+    }
+}
+
+fixed_size_enum! {
+    hir::Constness {
+        ( NotConst )
+        ( Const    )
+    }
+}
+
+fixed_size_enum! {
+    hir::Defaultness {
+        ( Final                        )
+        ( Default { has_value: false } )
+        ( Default { has_value: true }  )
+    }
+}
+
+fixed_size_enum! {
+    hir::IsAsync {
+        ( NotAsync )
+        ( Async    )
+    }
+}
+
+// We directly encode `DefPathHash` because a `Lazy` would encur a 25% cost.
+impl FixedSizeEncoding for Option<DefPathHash> {
+    type ByteArray = [u8; 16];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 16]) -> Self {
+        Some(DefPathHash(Fingerprint::from_le_bytes(*b)))
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 16]) {
+        let Some(DefPathHash(fingerprint)) = self else {
+            panic!("Trying to encode absent DefPathHash.")
+        };
+        *b = fingerprint.to_le_bytes();
+    }
+}
+
+// We directly encode RawDefId because using a `Lazy` would incur a 50% overhead in the worst case.
+impl FixedSizeEncoding for Option<RawDefId> {
+    type ByteArray = [u8; 8];
+
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let krate = u32::from_le_bytes(b[0..4].try_into().unwrap());
+        let index = u32::from_le_bytes(b[4..8].try_into().unwrap());
+        if krate == 0 {
+            return None;
+        }
+        Some(RawDefId { krate: krate - 1, index })
+    }
+
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        match self {
+            None => *b = [0; 8],
+            Some(RawDefId { krate, index }) => {
+                // CrateNum is less than `CrateNum::MAX_AS_U32`.
+                debug_assert!(krate < u32::MAX);
+                b[0..4].copy_from_slice(&(1 + krate).to_le_bytes());
+                b[4..8].copy_from_slice(&index.to_le_bytes());
+            }
+        }
     }
 }
 
@@ -80,44 +190,51 @@ fn write_to_bytes(self, b: &mut [u8]) {
 // generic `Lazy<T>` impl, but in the general case we might not need / want to
 // fit every `usize` in `u32`.
 impl<T> FixedSizeEncoding for Option<Lazy<T>> {
-    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN);
+    type ByteArray = [u8; 4];
 
-    fn from_bytes(b: &[u8]) -> Self {
-        Some(Lazy::from_position(NonZeroUsize::new(u32::from_bytes(b) as usize)?))
+    #[inline]
+    fn from_bytes(b: &[u8; 4]) -> Self {
+        let position = NonZeroUsize::new(u32::from_bytes(b) as usize)?;
+        Some(Lazy::from_position(position))
     }
 
-    fn write_to_bytes(self, b: &mut [u8]) {
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 4]) {
         let position = self.map_or(0, |lazy| lazy.position.get());
         let position: u32 = position.try_into().unwrap();
-
         position.write_to_bytes(b)
     }
 }
 
 impl<T> FixedSizeEncoding for Option<Lazy<[T]>> {
-    fixed_size_encoding_byte_len_and_defaults!(u32::BYTE_LEN * 2);
+    type ByteArray = [u8; 8];
 
-    fn from_bytes(b: &[u8]) -> Self {
-        Some(Lazy::from_position_and_meta(
-            <Option<Lazy<T>>>::from_bytes(b)?.position,
-            u32::from_bytes(&b[u32::BYTE_LEN..]) as usize,
-        ))
+    #[inline]
+    fn from_bytes(b: &[u8; 8]) -> Self {
+        let ([ref position_bytes, ref meta_bytes],[])= b.as_chunks::<4>() else { panic!() };
+        let position = NonZeroUsize::new(u32::from_bytes(position_bytes) as usize)?;
+        let len = u32::from_bytes(meta_bytes) as usize;
+        Some(Lazy::from_position_and_meta(position, len))
     }
 
-    fn write_to_bytes(self, b: &mut [u8]) {
-        self.map(|lazy| Lazy::<T>::from_position(lazy.position)).write_to_bytes(b);
+    #[inline]
+    fn write_to_bytes(self, b: &mut [u8; 8]) {
+        let ([ref mut position_bytes, ref mut meta_bytes],[])= b.as_chunks_mut::<4>() else { panic!() };
+
+        let position = self.map_or(0, |lazy| lazy.position.get());
+        let position: u32 = position.try_into().unwrap();
+        position.write_to_bytes(position_bytes);
 
         let len = self.map_or(0, |lazy| lazy.meta);
         let len: u32 = len.try_into().unwrap();
-
-        len.write_to_bytes(&mut b[u32::BYTE_LEN..]);
+        len.write_to_bytes(meta_bytes);
     }
 }
 
 /// Random-access table (i.e. offering constant-time `get`/`set`), similar to
 /// `Vec<Option<T>>`, but without requiring encoding or decoding all the values
 /// eagerly and in-order.
-/// A total of `(max_idx + 1) * <Option<T> as FixedSizeEncoding>::BYTE_LEN` bytes
+/// A total of `(max_idx + 1)` times `Option<T> as FixedSizeEncoding>::ByteArray`
 /// are used for a table, where `max_idx` is the largest index passed to
 /// `TableBuilder::set`.
 pub(super) struct Table<I: Idx, T>
@@ -135,12 +252,8 @@ pub(super) struct TableBuilder<I: Idx, T>
 where
     Option<T>: FixedSizeEncoding,
 {
-    // FIXME(eddyb) use `IndexVec<I, [u8; <Option<T>>::BYTE_LEN]>` instead of
-    // `Vec<u8>`, once that starts working (i.e. lazy normalization).
-    // Then again, that has the downside of not allowing `TableBuilder::encode` to
-    // obtain a `&[u8]` entirely in safe code, for writing the bytes out.
-    bytes: Vec<u8>,
-    _marker: PhantomData<(fn(&I), T)>,
+    blocks: IndexVec<I, <Option<T> as FixedSizeEncoding>::ByteArray>,
+    _marker: PhantomData<T>,
 }
 
 impl<I: Idx, T> Default for TableBuilder<I, T>
@@ -148,7 +261,7 @@ impl<I: Idx, T> Default for TableBuilder<I, T>
     Option<T>: FixedSizeEncoding,
 {
     fn default() -> Self {
-        TableBuilder { bytes: vec![], _marker: PhantomData }
+        TableBuilder { blocks: Default::default(), _marker: PhantomData }
     }
 }
 
@@ -156,25 +269,29 @@ impl<I: Idx, T> TableBuilder<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
-    pub(crate) fn set(&mut self, i: I, value: T) {
+    pub(crate) fn set<const N: usize>(&mut self, i: I, value: T)
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         // FIXME(eddyb) investigate more compact encodings for sparse tables.
         // On the PR @michaelwoerister mentioned:
         // > Space requirements could perhaps be optimized by using the HAMT `popcnt`
         // > trick (i.e. divide things into buckets of 32 or 64 items and then
         // > store bit-masks of which item in each bucket is actually serialized).
-        let i = i.index();
-        let needed = (i + 1) * <Option<T>>::BYTE_LEN;
-        if self.bytes.len() < needed {
-            self.bytes.resize(needed, 0);
-        }
-
-        Some(value).write_to_bytes_at(&mut self.bytes, i);
+        self.blocks.ensure_contains_elem(i, || [0; N]);
+        Some(value).write_to_bytes(&mut self.blocks[i]);
     }
 
-    pub(crate) fn encode(&self, buf: &mut Encoder) -> Lazy<Table<I, T>> {
+    pub(crate) fn encode<const N: usize>(&self, buf: &mut Encoder) -> Lazy<Table<I, T>>
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         let pos = buf.position();
-        buf.emit_raw_bytes(&self.bytes).unwrap();
-        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), self.bytes.len())
+        for block in &self.blocks {
+            buf.emit_raw_bytes(block).unwrap();
+        }
+        let num_bytes = self.blocks.len() * N;
+        Lazy::from_position_and_meta(NonZeroUsize::new(pos as usize).unwrap(), num_bytes)
     }
 }
 
@@ -182,6 +299,7 @@ impl<I: Idx, T> LazyMeta for Table<I, T>
 where
     Option<T>: FixedSizeEncoding,
 {
+    /// Number of bytes in the data stream.
     type Meta = usize;
 }
 
@@ -191,16 +309,28 @@ impl<I: Idx, T> Lazy<Table<I, T>>
 {
     /// Given the metadata, extract out the value at a particular index (if any).
     #[inline(never)]
-    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>>(&self, metadata: M, i: I) -> Option<T> {
+    pub(super) fn get<'a, 'tcx, M: Metadata<'a, 'tcx>, const N: usize>(
+        &self,
+        metadata: M,
+        i: I,
+    ) -> Option<T>
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
         debug!("Table::lookup: index={:?} len={:?}", i, self.meta);
 
         let start = self.position.get();
         let bytes = &metadata.blob()[start..start + self.meta];
-        <Option<T>>::maybe_read_from_bytes_at(bytes, i.index())?
+        let (bytes, []) = bytes.as_chunks::<N>() else { panic!() };
+        let bytes = bytes.get(i.index())?;
+        FixedSizeEncoding::from_bytes(bytes)
     }
 
     /// Size of the table in entries, including possible gaps.
-    pub(super) fn size(&self) -> usize {
-        self.meta / <Option<T>>::BYTE_LEN
+    pub(super) fn size<const N: usize>(&self) -> usize
+    where
+        Option<T>: FixedSizeEncoding<ByteArray = [u8; N]>,
+    {
+        self.meta / N
     }
 }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index fa2dad5..fd2b5f53 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -59,6 +59,7 @@
 #![feature(unwrap_infallible)]
 #![feature(decl_macro)]
 #![feature(drain_filter)]
+#![feature(intra_doc_pointers)]
 #![recursion_limit = "512"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index ff993ac..751c7f4 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -5,7 +5,7 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_macros::HashStable;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_span::def_id::LocalDefId;
 use std::hash::Hash;
 
@@ -58,9 +58,7 @@ fn default() -> Self {
 
 impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            let AccessLevels { ref map } = *self;
-            map.hash_stable(hcx, hasher);
-        });
+        let AccessLevels { ref map } = *self;
+        map.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 12fa5a1..98da20b 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -12,7 +12,7 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_macros::HashStable;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_span::{Span, DUMMY_SP};
 
 use std::fmt;
@@ -446,10 +446,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             ref yield_in_scope,
         } = *self;
 
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            root_body.hash_stable(hcx, hasher)
-        });
-
+        root_body.hash_stable(hcx, hasher);
         body_expr_count.hash_stable(hcx, hasher);
         parent_map.hash_stable(hcx, hasher);
         var_map.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 578fcd8..db7e973 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -9,13 +9,13 @@
 use crate::ty::codec::{TyDecoder, TyEncoder};
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
 use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::subst::{Subst, SubstsRef};
+use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
 
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::{CtorKind, Namespace};
-use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, GeneratorKind};
 use rustc_hir::{self as hir, HirId};
 use rustc_session::Session;
@@ -127,12 +127,24 @@ fn is_mir_dump_enabled(&self) -> bool {
 /// The various "big phases" that MIR goes through.
 ///
 /// These phases all describe dialects of MIR. Since all MIR uses the same datastructures, the
-/// dialects forbid certain variants or values in certain phases.
+/// dialects forbid certain variants or values in certain phases. The sections below summarize the
+/// changes, but do not document them thoroughly. The full documentation is found in the appropriate
+/// documentation for the thing the change is affecting.
 ///
 /// Warning: ordering of variants is significant.
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
 pub enum MirPhase {
+    /// The dialect of MIR used during all phases before `DropsLowered` is the same. This is also
+    /// the MIR that analysis such as borrowck uses.
+    ///
+    /// One important thing to remember about the behavior of this section of MIR is that drop terminators
+    /// (including drop and replace) are *conditional*. The elaborate drops pass will then replace each
+    /// instance of a drop terminator with a nop, an unconditional drop, or a drop conditioned on a drop
+    /// flag. Of course, this means that it is important that the drop elaboration can accurately recognize
+    /// when things are initialized and when things are de-initialized. That means any code running on this
+    /// version of MIR must be sure to produce output that drop elaboration can reason about. See the
+    /// section on the drop terminatorss for more details.
     Built = 0,
     // FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
     // We used to have this for pre-miri MIR based const eval.
@@ -162,6 +174,16 @@ pub enum MirPhase {
     /// And the following variant is allowed:
     /// * [`StatementKind::SetDiscriminant`]
     Deaggregated = 4,
+    /// Before this phase, generators are in the "source code" form, featuring `yield` statements
+    /// and such. With this phase change, they are transformed into a proper state machine. Running
+    /// optimizations before this change can be potentially dangerous because the source code is to
+    /// some extent a "lie." In particular, `yield` terminators effectively make the value of all
+    /// locals visible to the caller. This means that dead store elimination before them, or code
+    /// motion across them, is not correct in general. This is also exasperated by type checking
+    /// having pre-computed a list of the types that it thinks are ok to be live across a yield
+    /// point - this is necessary to decide eg whether autotraits are implemented. Introducing new
+    /// types across a yield point will lead to ICEs becaues of this.
+    ///
     /// Beginning with this phase, the following variants are disallowed:
     /// * [`TerminatorKind::Yield`](terminator::TerminatorKind::Yield)
     /// * [`TerminatorKind::GeneratorDrop](terminator::TerminatorKind::GeneratorDrop)
@@ -1573,18 +1595,45 @@ pub fn replace_nop(&mut self) -> Self {
 /// causing an ICE if they are violated.
 #[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum StatementKind<'tcx> {
-    /// Write the RHS Rvalue to the LHS Place.
+    /// Assign statements roughly correspond to an assignment in Rust proper (`x = ...`) except
+    /// without the possibility of dropping the previous value (that must be done separately, if at
+    /// all). The *exact* way this works is undecided. It probably does something like evaluating
+    /// the LHS to a place and the RHS to a value, and then storing the value to the place. Various
+    /// parts of this may do type specific things that are more complicated than simply copying
+    /// bytes.
     ///
-    /// The LHS place may not overlap with any memory accessed on the RHS.
+    /// **Needs clarification**: The implication of the above idea would be that assignment implies
+    /// that the resulting value is initialized. I believe we could commit to this separately from
+    /// committing to whatever part of the memory model we would need to decide on to make the above
+    /// paragragh precise. Do we want to?
+    ///
+    /// Assignments in which the types of the place and rvalue differ are not well-formed.
+    ///
+    /// **Needs clarification**: Do we ever want to worry about non-free (in the body) lifetimes for
+    /// the typing requirement in post drop-elaboration MIR? I think probably not - I'm not sure we
+    /// could meaningfully require this anyway. How about free lifetimes? Is ignoring this
+    /// interesting for optimizations? Do we want to allow such optimizations?
+    ///
+    /// **Needs clarification**: We currently require that the LHS place not overlap with any place
+    /// read as part of computation of the RHS for some rvalues (generally those not producing
+    /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion,
+    /// it is also unclear in what order the components are evaluated.
+    ///
+    /// [#68364]: https://github.com/rust-lang/rust/issues/68364
+    ///
+    /// See [`Rvalue`] documentation for details on each of those.
     Assign(Box<(Place<'tcx>, Rvalue<'tcx>)>),
 
-    /// This represents all the reading that a pattern match may do
-    /// (e.g., inspecting constants and discriminant values), and the
-    /// kind of pattern it comes from. This is in order to adapt potential
-    /// error messages to these specific patterns.
+    /// This represents all the reading that a pattern match may do (e.g., inspecting constants and
+    /// discriminant values), and the kind of pattern it comes from. This is in order to adapt
+    /// potential error messages to these specific patterns.
     ///
     /// Note that this also is emitted for regular `let` bindings to ensure that locals that are
     /// never accessed still get some sanity checks for, e.g., `let x: ! = ..;`
+    ///
+    /// When executed at runtime this is a nop.
+    ///
+    /// Disallowed after drop elaboration.
     FakeRead(Box<(FakeReadCause, Place<'tcx>)>),
 
     /// Write the discriminant for a variant to the enum Place.
@@ -1599,17 +1648,35 @@ pub enum StatementKind<'tcx> {
     /// This writes `uninit` bytes to the entire place.
     Deinit(Box<Place<'tcx>>),
 
-    /// Start a live range for the storage of the local.
+    /// `StorageLive` and `StorageDead` statements mark the live range of a local.
+    ///
+    /// Using a local before a `StorageLive` or after a `StorageDead` is not well-formed. These
+    /// statements are not required. If the entire MIR body contains no `StorageLive`/`StorageDead`
+    /// statements for a particular local, the local is always considered live.
+    ///
+    /// More precisely, the MIR validator currently does a `MaybeStorageLiveLocals` analysis to
+    /// check validity of each use of a local. I believe this is equivalent to requiring for every
+    /// use of a local, there exist at least one path from the root to that use that contains a
+    /// `StorageLive` more recently than a `StorageDead`.
+    ///
+    /// **Needs clarification**: Is it permitted to have two `StorageLive`s without an intervening
+    /// `StorageDead`? Two `StorageDead`s without an intervening `StorageLive`? LLVM says poison,
+    /// yes. If the answer to any of these is "no," is breaking that rule UB or is it an error to
+    /// have a path in the CFG that might do this?
     StorageLive(Local),
 
-    /// End the current live range for the storage of the local.
+    /// See `StorageLive` above.
     StorageDead(Local),
 
-    /// Retag references in the given place, ensuring they got fresh tags. This is
-    /// part of the Stacked Borrows model. These statements are currently only interpreted
-    /// by miri and only generated when "-Z mir-emit-retag" is passed.
-    /// See <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/>
-    /// for more details.
+    /// Retag references in the given place, ensuring they got fresh tags.
+    ///
+    /// This is part of the Stacked Borrows model. These statements are currently only interpreted
+    /// by miri and only generated when `-Z mir-emit-retag` is passed. See
+    /// <https://internals.rust-lang.org/t/stacked-borrows-an-aliasing-model-for-rust/8153/> for
+    /// more details.
+    ///
+    /// For code that is not specific to stacked borrows, you should consider retags to read
+    /// and modify the place in an opaque way.
     Retag(RetagKind, Box<Place<'tcx>>),
 
     /// Encodes a user's type ascription. These need to be preserved
@@ -1624,6 +1691,10 @@ pub enum StatementKind<'tcx> {
     /// - `Contravariant` -- requires that `T_y :> T`
     /// - `Invariant` -- requires that `T_y == T`
     /// - `Bivariant` -- no effect
+    ///
+    /// When executed at runtime this is a nop.
+    ///
+    /// Disallowed after drop elaboration.
     AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
 
     /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
@@ -1633,9 +1704,19 @@ pub enum StatementKind<'tcx> {
     /// executed.
     Coverage(Box<Coverage>),
 
-    /// Denotes a call to the intrinsic function copy_overlapping, where `src_dst` denotes the
-    /// memory being read from and written to(one field to save memory), and size
-    /// indicates how many bytes are being copied over.
+    /// Denotes a call to the intrinsic function `copy_nonoverlapping`.
+    ///
+    /// First, all three operands are evaluated. `src` and `dest` must each be a reference, pointer,
+    /// or `Box` pointing to the same type `T`. `count` must evaluate to a `usize`. Then, `src` and
+    /// `dest` are dereferenced, and `count * size_of::<T>()` bytes beginning with the first byte of
+    /// the `src` place are copied to the continguous range of bytes beginning with the first byte
+    /// of `dest`.
+    ///
+    /// **Needs clarification**: In what order are operands computed and dereferenced? It should
+    /// probably match the order for assignment, but that is also undecided.
+    ///
+    /// **Needs clarification**: Is this typed or not, ie is there a typed load and store involved?
+    /// I vaguely remember Ralf saying somewhere that he thought it should not be.
     CopyNonOverlapping(Box<CopyNonOverlapping<'tcx>>),
 
     /// No-op. Useful for deleting instructions without affecting statement indices.
@@ -1785,8 +1866,82 @@ pub struct CopyNonOverlapping<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 // Places
 
-/// A path to a value; something that can be evaluated without
-/// changing or disturbing program state.
+/// Places roughly correspond to a "location in memory." Places in MIR are the same mathematical
+/// object as places in Rust. This of course means that what exactly they are is undecided and part
+/// of the Rust memory model. However, they will likely contain at least the following pieces of
+/// information in some form:
+///
+///  1. The address in memory that the place refers to.
+///  2. The provenance with which the place is being accessed.
+///  3. The type of the place and an optional variant index. See [`PlaceTy`][tcx::PlaceTy].
+///  4. Optionally, some metadata. This exists if and only if the type of the place is not `Sized`.
+///
+/// We'll give a description below of how all pieces of the place except for the provenance are
+/// calculated. We cannot give a description of the provenance, because that is part of the
+/// undecided aliasing model - we only include it here at all to acknowledge its existence.
+///
+/// Each local naturally corresponds to the place `Place { local, projection: [] }`. This place has
+/// the address of the local's allocation and the type of the local.
+///
+/// **Needs clarification:** Unsized locals seem to present a bit of an issue. Their allocation
+/// can't actually be created on `StorageLive`, because it's unclear how big to make the allocation.
+/// Furthermore, MIR produces assignments to unsized locals, although that is not permitted under
+/// `#![feature(unsized_locals)]` in Rust. Besides just putting "unsized locals are special and
+/// different" in a bunch of places, I (JakobDegen) don't know how to incorporate this behavior into
+/// the current MIR semantics in a clean way - possibly this needs some design work first.
+///
+/// For places that are not locals, ie they have a non-empty list of projections, we define the
+/// values as a function of the parent place, that is the place with its last [`ProjectionElem`]
+/// stripped. The way this is computed of course depends on the kind of that last projection
+/// element:
+///
+///  - [`Downcast`](ProjectionElem::Downcast): This projection sets the place's variant index to the
+///    given one, and makes no other changes. A `Downcast` projection on a place with its variant
+///    index already set is not well-formed.
+///  - [`Field`](ProjectionElem::Field): `Field` projections take their parent place and create a
+///    place referring to one of the fields of the type. The resulting address is the parent
+///    address, plus the offset of the field. The type becomes the type of the field. If the parent
+///    was unsized and so had metadata associated with it, then the metadata is retained if the
+///    field is unsized and thrown out if it is sized.
+///
+///    These projections are only legal for tuples, ADTs, closures, and generators. If the ADT or
+///    generator has more than one variant, the parent place's variant index must be set, indicating
+///    which variant is being used. If it has just one variant, the variant index may or may not be
+///    included - the single possible variant is inferred if it is not included.
+///  - [`ConstantIndex`](ProjectionElem::ConstantIndex): Computes an offset in units of `T` into the
+///    place as described in the documentation for the `ProjectionElem`. The resulting address is
+///    the parent's address plus that offset, and the type is `T`. This is only legal if the parent
+///    place has type `[T;  N]` or `[T]` (*not* `&[T]`). Since such a `T` is always sized, any
+///    resulting metadata is thrown out.
+///  - [`Subslice`](ProjectionElem::Subslice): This projection calculates an offset and a new
+///    address in a similar manner as `ConstantIndex`. It is also only legal on `[T; N]` and `[T]`.
+///    However, this yields a `Place` of type `[T]`, and additionally sets the metadata to be the
+///    length of the subslice.
+///  - [`Index`](ProjectionElem::Index): Like `ConstantIndex`, only legal on `[T; N]` or `[T]`.
+///    However, `Index` additionally takes a local from which the value of the index is computed at
+///    runtime. Computing the value of the index involves interpreting the `Local` as a
+///    `Place { local, projection: [] }`, and then computing its value as if done via
+///    [`Operand::Copy`]. The array/slice is then indexed with the resulting value. The local must
+///    have type `usize`.
+///  - [`Deref`](ProjectionElem::Deref): Derefs are the last type of projection, and the most
+///    complicated. They are only legal on parent places that are references, pointers, or `Box`. A
+///    `Deref` projection begins by loading a value from the parent place, as if by
+///    [`Operand::Copy`]. It then dereferences the resulting pointer, creating a place of the
+///    pointee's type. The resulting address is the address that was stored in the pointer. If the
+///    pointee type is unsized, the pointer additionally stored the value of the metadata.
+///
+/// Computing a place may cause UB. One possibility is that the pointer used for a `Deref` may not
+/// be suitably aligned. Another possibility is that the place is not in bounds, meaning it does not
+/// point to an actual allocation.
+///
+/// However, if this is actually UB and when the UB kicks in is undecided. This is being discussed
+/// in [UCG#319]. The options include that every place must obey those rules, that only some places
+/// must obey them, or that places impose no rules of their own.
+///
+/// [UCG#319]: https://github.com/rust-lang/unsafe-code-guidelines/issues/319
+///
+/// Rust currently requires that every place obey those two rules. This is checked by MIRI and taken
+/// advantage of by codegen (via `gep inbounds`). That is possibly subject to change.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
 pub struct Place<'tcx> {
     pub local: Local,
@@ -2155,24 +2310,39 @@ pub struct SourceScopeLocalData {
 ///////////////////////////////////////////////////////////////////////////
 // Operands
 
-/// These are values that can appear inside an rvalue. They are intentionally
-/// limited to prevent rvalues from being nested in one another.
+/// An operand in MIR represents a "value" in Rust, the definition of which is undecided and part of
+/// the memory model. One proposal for a definition of values can be found [on UCG][value-def].
+///
+/// [value-def]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/value-domain.md
+///
+/// The most common way to create values is via loading a place. Loading a place is an operation
+/// which reads the memory of the place and converts it to a value. This is a fundamentally *typed*
+/// operation. The nature of the value produced depends on the type of the conversion. Furthermore,
+/// there may be other effects: if the type has a validity constraint loading the place might be UB
+/// if the validity constraint is not met.
+///
+/// **Needs clarification:** Ralf proposes that loading a place not have side-effects.
+/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
+/// something we can even decide without knowing more about Rust's memory model?
+///
+/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri
+/// currently implements it, but it seems like this may be something to check against in the
+/// validator.
 #[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
-    /// Copy: The value must be available for use afterwards.
-    ///
-    /// This implies that the type of the place must be `Copy`; this is true
-    /// by construction during build, but also checked by the MIR type checker.
+    /// Creates a value by loading the given place. The type of the place must be `Copy`
     Copy(Place<'tcx>),
 
-    /// Move: The value (including old borrows of it) will not be used again.
+    /// Creates a value by performing loading the place, just like the `Copy` operand.
     ///
-    /// Safe for values of all types (modulo future developments towards `?Move`).
-    /// Correct usage patterns are enforced by the borrow checker for safe code.
-    /// `Copy` may be converted to `Move` to enable "last-use" optimizations.
+    /// This *may* additionally overwrite the place with `uninit` bytes, depending on how we decide
+    /// in [UCG#188]. You should not emit MIR that may attempt a subsequent second load of this
+    /// place without first re-initializing it.
+    ///
+    /// [UCG#188]: https://github.com/rust-lang/unsafe-code-guidelines/issues/188
     Move(Place<'tcx>),
 
-    /// Synthesizes a constant value.
+    /// Constants are already semantically values, and remain unchanged.
     Constant(Box<Constant<'tcx>>),
 }
 
@@ -2280,57 +2450,134 @@ pub fn const_fn_def(&self) -> Option<(DefId, SubstsRef<'tcx>)> {
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 /// The various kinds of rvalues that can appear in MIR.
 ///
-/// Not all of these are allowed at every [`MirPhase`]. Check the documentation there to see which
-/// ones you do not have to worry about. The MIR validator will generally enforce such restrictions,
-/// causing an ICE if they are violated.
+/// Not all of these are allowed at every [`MirPhase`] - when this is the case, it's stated below.
+///
+/// Computing any rvalue begins by evaluating the places and operands in some order (**Needs
+/// clarification**: Which order?). These are then used to produce a "value" - the same kind of
+/// value that an [`Operand`] produces.
 pub enum Rvalue<'tcx> {
-    /// x (either a move or copy, depending on type of x)
+    /// Yields the operand unchanged
     Use(Operand<'tcx>),
 
-    /// [x; 32]
+    /// Creates an array where each element is the value of the operand.
+    ///
+    /// This is the cause of a bug in the case where the repetition count is zero because the value
+    /// is not dropped, see [#74836].
+    ///
+    /// Corresponds to source code like `[x; 32]`.
+    ///
+    /// [#74836]: https://github.com/rust-lang/rust/issues/74836
     Repeat(Operand<'tcx>, ty::Const<'tcx>),
 
-    /// &x or &mut x
+    /// Creates a reference of the indicated kind to the place.
+    ///
+    /// There is not much to document here, because besides the obvious parts the semantics of this
+    /// are essentially entirely a part of the aliasing model. There are many UCG issues discussing
+    /// exactly what the behavior of this operation should be.
+    ///
+    /// `Shallow` borrows are disallowed after drop lowering.
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
 
-    /// Accessing a thread local static. This is inherently a runtime operation, even if llvm
-    /// treats it as an access to a static. This `Rvalue` yields a reference to the thread local
-    /// static.
+    /// Creates a pointer/reference to the given thread local.
+    ///
+    /// The yielded type is a `*mut T` if the static is mutable, otherwise if the static is extern a
+    /// `*const T`, and if neither of those apply a `&T`.
+    ///
+    /// **Note:** This is a runtime operation that actually executes code and is in this sense more
+    /// like a function call. Also, eliminating dead stores of this rvalue causes `fn main() {}` to
+    /// SIGILL for some reason that I (JakobDegen) never got a chance to look into.
+    ///
+    /// **Needs clarification**: Are there weird additional semantics here related to the runtime
+    /// nature of this operation?
     ThreadLocalRef(DefId),
 
-    /// Create a raw pointer to the given place
-    /// Can be generated by raw address of expressions (`&raw const x`),
-    /// or when casting a reference to a raw pointer.
+    /// Creates a pointer with the indicated mutability to the place.
+    ///
+    /// This is generated by pointer casts like `&v as *const _` or raw address of expressions like
+    /// `&raw v` or `addr_of!(v)`.
+    ///
+    /// Like with references, the semantics of this operation are heavily dependent on the aliasing
+    /// model.
     AddressOf(Mutability, Place<'tcx>),
 
-    /// length of a `[X]` or `[X;n]` value
+    /// Yields the length of the place, as a `usize`.
+    ///
+    /// If the type of the place is an array, this is the array length. For slices (`[T]`, not
+    /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is
+    /// ill-formed for places of other types.
     Len(Place<'tcx>),
 
+    /// Performs essentially all of the casts that can be performed via `as`.
+    ///
+    /// This allows for casts from/to a variety of types.
+    ///
+    /// **FIXME**: Document exactly which `CastKind`s allow which types of casts. Figure out why
+    /// `ArrayToPointer` and `MutToConstPointer` are special.
     Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
 
+    /// * `Offset` has the same semantics as [`offset`](pointer::offset), except that the second
+    ///   parameter may be a `usize` as well.
+    /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats,
+    ///   raw pointers, or function pointers of matching types and return a `bool`.
+    /// * Left and right shift operations accept signed or unsigned integers not necessarily of the
+    ///   same type and return a value of the same type as their LHS. Like in Rust, the RHS is
+    ///   truncated as needed.
+    /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
+    ///   types and return a value of that type.
+    /// * The remaining operations accept signed integers, unsigned integers, or floats with
+    ///   matching types and return a value of that type.
     BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
+
+    /// Same as `BinaryOp`, but yields `(T, bool)` instead of `T`. In addition to performing the
+    /// same computation as the matching `BinaryOp`, checks if the infinite precison result would be
+    /// unequal to the actual result and sets the `bool` if this is the case.
+    ///
+    /// This only supports addition, subtraction, multiplication, and shift operations on integers.
     CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
+    /// Computes a value as described by the operation.
     NullaryOp(NullOp, Ty<'tcx>),
+
+    /// Exactly like `BinaryOp`, but less operands.
+    ///
+    /// Also does two's-complement arithmetic. Negation requires a signed integer or a float;
+    /// bitwise not requires a signed integer, unsigned integer, or bool. Both operation kinds
+    /// return a value with the same type as their operand.
     UnaryOp(UnOp, Operand<'tcx>),
 
-    /// Read the discriminant of an ADT.
+    /// Computes the discriminant of the place, returning it as an integer of type
+    /// [`discriminant_ty`].
     ///
-    /// Undefined (i.e., no effort is made to make it defined, but there’s no reason why it cannot
-    /// be defined to return, say, a 0) if ADT is not an enum.
+    /// The validity requirements for the underlying value are undecided for this rvalue, see
+    /// [#91095]. Note too that the value of the discriminant is not the same thing as the
+    /// variant index; use [`discriminant_for_variant`] to convert.
+    ///
+    /// For types defined in the source code as enums, this is well behaved. This is also well
+    /// formed for other types, but yields no particular value - there is no reason it couldn't be
+    /// defined to yield eg zero though.
+    ///
+    /// [`discriminant_ty`]: crate::ty::Ty::discriminant_ty
+    /// [#91095]: https://github.com/rust-lang/rust/issues/91095
+    /// [`discriminant_for_variant`]: crate::ty::Ty::discriminant_for_variant
     Discriminant(Place<'tcx>),
 
-    /// Creates an aggregate value, like a tuple or struct. This is
-    /// only needed because we want to distinguish `dest = Foo { x:
-    /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
-    /// that `Foo` has a destructor. These rvalues can be optimized
-    /// away after type-checking and before lowering.
+    /// Creates an aggregate value, like a tuple or struct.
+    ///
+    /// This is needed because dataflow analysis needs to distinguish
+    /// `dest = Foo { x: ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case that `Foo`
+    /// has a destructor.
+    ///
+    /// Disallowed after deaggregation for all aggregate kinds except `Array` and `Generator`. After
+    /// generator lowering, `Generator` aggregate kinds are disallowed too.
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
 
     /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
     ///
-    /// This is different a normal transmute because dataflow analysis will treat the box
-    /// as initialized but its content as uninitialized.
+    /// This is different from a normal transmute because dataflow analysis will treat the box as
+    /// initialized but its content as uninitialized. Like other pointer casts, this in general
+    /// affects alias analysis.
+    ///
+    /// Disallowed after drop elaboration.
     ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
 }
 
@@ -2674,6 +2921,16 @@ pub fn ty(&self) -> Ty<'tcx> {
         }
     }
 
+    pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
+        match self {
+            ConstantKind::Ty(c) => match c.val() {
+                ty::ConstKind::Value(v) => Some(v),
+                _ => None,
+            },
+            ConstantKind::Val(v, _) => Some(*v),
+        }
+    }
+
     #[inline]
     pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
         match self {
@@ -2703,6 +2960,32 @@ pub fn try_to_bool(self) -> Option<bool> {
     }
 
     #[inline]
+    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        match self {
+            Self::Ty(c) => {
+                // FIXME Need to use a different evaluation function that directly returns a `ConstValue`
+                // if evaluation succeeds and does not create a ValTree first
+                if let Some(val) = c.val().try_eval(tcx, param_env) {
+                    match val {
+                        Ok(val) => Self::Val(val, c.ty()),
+                        Err(_) => Self::Ty(tcx.const_error(self.ty())),
+                    }
+                } else {
+                    self
+                }
+            }
+            Self::Val(_, _) => self,
+        }
+    }
+
+    /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
+    #[inline]
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+        self.try_eval_bits(tcx, param_env, ty)
+            .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
+    }
+
+    #[inline]
     pub fn try_eval_bits(
         &self,
         tcx: TyCtxt<'tcx>,
@@ -2736,25 +3019,142 @@ pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -
         }
     }
 
+    pub fn from_bits(
+        tcx: TyCtxt<'tcx>,
+        bits: u128,
+        param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
+    ) -> Self {
+        let size = tcx
+            .layout_of(param_env_ty)
+            .unwrap_or_else(|e| {
+                bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
+            })
+            .size;
+        let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
+
+        Self::Val(cv, param_env_ty.value)
+    }
+
     pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
         let cv = ConstValue::from_bool(v);
         Self::Val(cv, tcx.types.bool)
     }
 
-    pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
+    pub fn zero_sized(ty: Ty<'tcx>) -> Self {
         let cv = ConstValue::Scalar(Scalar::ZST);
         Self::Val(cv, ty)
     }
 
     pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
         let ty = tcx.types.usize;
-        let size = tcx
-            .layout_of(ty::ParamEnv::empty().and(ty))
-            .unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
-            .size;
-        let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
+        Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
+    }
 
-        Self::Val(cv, ty)
+    /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
+    /// converted to a constant, everything else becomes `Unevaluated`.
+    pub fn from_anon_const(
+        tcx: TyCtxt<'tcx>,
+        def_id: LocalDefId,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Self {
+        Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
+    }
+
+    #[instrument(skip(tcx), level = "debug")]
+    fn from_opt_const_arg_anon_const(
+        tcx: TyCtxt<'tcx>,
+        def: ty::WithOptConstParam<LocalDefId>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> Self {
+        let body_id = match tcx.hir().get_by_def_id(def.did) {
+            hir::Node::AnonConst(ac) => ac.body,
+            _ => span_bug!(
+                tcx.def_span(def.did.to_def_id()),
+                "from_anon_const can only process anonymous constants"
+            ),
+        };
+
+        let expr = &tcx.hir().body(body_id).value;
+        debug!(?expr);
+
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        let expr = match &expr.kind {
+            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+                block.expr.as_ref().unwrap()
+            }
+            _ => expr,
+        };
+
+        let ty = tcx.type_of(def.def_id_for_type_of());
+
+        // FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
+        // does not provide the parents generics to anonymous constants. We still allow generic const
+        // parameters by themselves however, e.g. `N`.  These constants would cause an ICE if we were to
+        // ever try to substitute the generic parameters in their bodies.
+        //
+        // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
+        // cause issues if we were to remove that special-case and try to evaluate the constant instead.
+        use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
+        match expr.kind {
+            ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
+                // Find the name and index of the const parameter by indexing the generics of
+                // the parent item and construct a `ParamConst`.
+                let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+                let item_id = tcx.hir().get_parent_node(hir_id);
+                let item_def_id = tcx.hir().local_def_id(item_id);
+                let generics = tcx.generics_of(item_def_id.to_def_id());
+                let index = generics.param_def_id_to_index[&def_id];
+                let name = tcx.hir().name(hir_id);
+                let ty_const = tcx.mk_const(ty::ConstS {
+                    val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+                    ty,
+                });
+
+                return Self::Ty(ty_const);
+            }
+            _ => {}
+        }
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+        let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
+            if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
+                InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
+            } else {
+                tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
+            }
+        } else {
+            tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
+        };
+        debug!(?parent_substs);
+
+        let did = def.did.to_def_id();
+        let child_substs = InternalSubsts::identity_for_item(tcx, did);
+        let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
+        debug!(?substs);
+
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+        let span = tcx.hir().span(hir_id);
+        let uneval = ty::Unevaluated::new(def.to_global(), substs);
+        debug!(?span, ?param_env);
+
+        match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
+            Ok(val) => Self::Val(val, ty),
+            Err(_) => {
+                // Error was handled in `const_eval_resolve`. Here we just create a
+                // new unevaluated const and error hard later in codegen
+                let ty_const = tcx.mk_const(ty::ConstS {
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+                        def: def.to_global(),
+                        substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
+                        promoted: None,
+                    }),
+                    ty,
+                });
+
+                Self::Ty(ty_const)
+            }
+        }
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index 13c325a..f76217d 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -8,7 +8,7 @@
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc_hir::ItemId;
 use rustc_index::vec::Idx;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_session::config::OptLevel;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -40,7 +40,7 @@ pub enum InstantiationMode {
     LocalCopy,
 }
 
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash, HashStable)]
 pub enum MonoItem<'tcx> {
     Fn(Instance<'tcx>),
     Static(DefId),
@@ -202,26 +202,6 @@ pub fn krate(&self) -> CrateNum {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        ::std::mem::discriminant(self).hash_stable(hcx, hasher);
-
-        match *self {
-            MonoItem::Fn(ref instance) => {
-                instance.hash_stable(hcx, hasher);
-            }
-            MonoItem::Static(def_id) => {
-                def_id.hash_stable(hcx, hasher);
-            }
-            MonoItem::GlobalAsm(item_id) => {
-                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                    item_id.hash_stable(hcx, hasher);
-                })
-            }
-        }
-    }
-}
-
 impl<'tcx> fmt::Display for MonoItem<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 51d8113..597ade4 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -76,6 +76,9 @@ pub fn projection_ty_core<V, T>(
         V: ::std::fmt::Debug,
         T: ::std::fmt::Debug + Copy,
     {
+        if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) {
+            bug!("cannot use non field projection on downcasted place")
+        }
         let answer = match *elem {
             ProjectionElem::Deref => {
                 let ty = self
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index ae94bd1..cc08857 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -105,13 +105,34 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
+/// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
+/// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
+/// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
+/// once the current function is reached, execution continues at the given basic block, if any. If
+/// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
+/// equivalent to the execution of a `Resume` terminator.
+///
+/// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
+/// basic blocks have a couple restrictions:
+///  1. All `cleanup` fields in them must be `None`.
+///  2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
+///  3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
+///     must also be `cleanup`. This is a part of the type system and checked statically, so it is
+///     still an error to have such an edge in the CFG even if it's known that it won't be taken at
+///     runtime.
 #[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
-    /// Block should have one successor in the graph; we jump there.
+    /// Block has one successor; we continue execution there.
     Goto { target: BasicBlock },
 
-    /// Operand evaluates to an integer; jump depending on its value
-    /// to one of the targets, and otherwise fallback to `otherwise`.
+    /// Switches based on the computed value.
+    ///
+    /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
+    /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
+    /// contains the computed value, continues execution at the associated basic block. Otherwise,
+    /// continues execution at the "otherwise" basic block.
+    ///
+    /// Target values may not appear more than once.
     SwitchInt {
         /// The discriminant value being tested.
         discr: Operand<'tcx>,
@@ -124,29 +145,62 @@ pub enum TerminatorKind<'tcx> {
         targets: SwitchTargets,
     },
 
-    /// Indicates that the landing pad is finished and unwinding should
-    /// continue. Emitted by `build::scope::diverge_cleanup`.
+    /// Indicates that the landing pad is finished and that the process should continue unwinding.
+    ///
+    /// Like a return, this marks the end of this invocation of the function.
+    ///
+    /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
+    /// deaggregation runs.
     Resume,
 
-    /// Indicates that the landing pad is finished and that the process
-    /// should abort. Used to prevent unwinding for foreign items.
+    /// Indicates that the landing pad is finished and that the process should abort.
+    ///
+    /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
+    /// cleanup blocks.
     Abort,
 
-    /// Indicates a normal return. The return place should have
-    /// been filled in before this executes. This can occur multiple times
-    /// in different basic blocks.
+    /// Returns from the function.
+    ///
+    /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
+    /// likely at least assigns the value currently in the return place (`_0`) to the place
+    /// specified in the associated `Call` terminator in the calling function, as if assigned via
+    /// `dest = move _0`. It might additionally do other things, like have side-effects in the
+    /// aliasing model.
+    ///
+    /// If the body is a generator body, this has slightly different semantics; it instead causes a
+    /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
+    /// to the return place.
     Return,
 
     /// Indicates a terminator that can never be reached.
+    ///
+    /// Executing this terminator is UB.
     Unreachable,
 
-    /// Drop the `Place`.
+    /// The behavior of this statement differs significantly before and after drop elaboration.
+    /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
+    /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
+    /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
+    /// issue tracking if drop glue has any interesting semantics in addition to those of a function
+    /// call?)
+    ///
+    /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
+    /// `Drop` will be executed if...
+    ///
+    /// **Needs clarification**: End of that sentence. This in effect should document the exact
+    /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
+    ///
+    /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
+    /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
+    /// > consider indirect assignments.
     Drop { place: Place<'tcx>, target: BasicBlock, unwind: Option<BasicBlock> },
 
-    /// Drop the `Place` and assign the new value over it. This ensures
-    /// that the assignment to `P` occurs *even if* the destructor for
-    /// place unwinds. Its semantics are best explained by the
-    /// elaboration:
+    /// Drops the place and assigns a new value to it.
+    ///
+    /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
+    /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
+    /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
+    /// explained by the elaboration:
     ///
     /// ```
     /// BB0 {
@@ -170,7 +224,7 @@ pub enum TerminatorKind<'tcx> {
     /// }
     /// ```
     ///
-    /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass.
+    /// Disallowed after drop elaboration.
     DropAndReplace {
         place: Place<'tcx>,
         value: Operand<'tcx>,
@@ -178,7 +232,16 @@ pub enum TerminatorKind<'tcx> {
         unwind: Option<BasicBlock>,
     },
 
-    /// Block ends with a call of a function.
+    /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
+    /// the referred to function. The operand types must match the argument types of the function.
+    /// The return place type must match the return type. The type of the `func` operand must be
+    /// callable, meaning either a function pointer, a function type, or a closure type.
+    ///
+    /// **Needs clarification**: The exact semantics of this. Current backends rely on `move`
+    /// operands not aliasing the return place. It is unclear how this is justified in MIR, see
+    /// [#71117].
+    ///
+    /// [#71117]: https://github.com/rust-lang/rust/issues/71117
     Call {
         /// The function that’s being called.
         func: Operand<'tcx>,
@@ -187,7 +250,7 @@ pub enum TerminatorKind<'tcx> {
         /// This allows the memory occupied by "by-value" arguments to be
         /// reused across function calls without duplicating the contents.
         args: Vec<Operand<'tcx>>,
-        /// Destination for the return value. If some, the call is converging.
+        /// Destination for the return value. If none, the call necessarily diverges.
         destination: Option<(Place<'tcx>, BasicBlock)>,
         /// Cleanups to be done if the call unwinds.
         cleanup: Option<BasicBlock>,
@@ -199,8 +262,12 @@ pub enum TerminatorKind<'tcx> {
         fn_span: Span,
     },
 
-    /// Jump to the target if the condition has the expected value,
-    /// otherwise panic with a message and a cleanup target.
+    /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
+    /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
+    /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
+    /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
+    /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
+    /// assertion does not fail, execution continues at the specified basic block.
     Assert {
         cond: Operand<'tcx>,
         expected: bool,
@@ -209,7 +276,18 @@ pub enum TerminatorKind<'tcx> {
         cleanup: Option<BasicBlock>,
     },
 
-    /// A suspend point.
+    /// Marks a suspend point.
+    ///
+    /// Like `Return` terminators in generator bodies, this computes `value` and then a
+    /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
+    /// the return place of the function calling this one, and execution continues in the calling
+    /// function. When next invoked with the same first argument, execution of this function
+    /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
+    /// place. If the generator is dropped before then, the `drop` basic block is invoked.
+    ///
+    /// Not permitted in bodies that are not generator bodies, or after generator lowering.
+    ///
+    /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
     Yield {
         /// The value to return.
         value: Operand<'tcx>,
@@ -221,11 +299,24 @@ pub enum TerminatorKind<'tcx> {
         drop: Option<BasicBlock>,
     },
 
-    /// Indicates the end of the dropping of a generator.
+    /// Indicates the end of dropping a generator.
+    ///
+    /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations
+    /// as `yield`.
+    ///
+    /// **Needs clarification**: Is that even correct? The generator drop code is always confusing
+    /// to me, because it's not even really in the current body.
+    ///
+    /// **Needs clarification**: Are there type system constraints on these terminators? Should
+    /// there be a "block type" like `cleanup` blocks for them?
     GeneratorDrop,
 
-    /// A block where control flow only ever takes one real path, but borrowck
-    /// needs to be more conservative.
+    /// A block where control flow only ever takes one real path, but borrowck needs to be more
+    /// conservative.
+    ///
+    /// At runtime this is semantically just a goto.
+    ///
+    /// Disallowed after drop elaboration.
     FalseEdge {
         /// The target normal control flow will take.
         real_target: BasicBlock,
@@ -233,9 +324,14 @@ pub enum TerminatorKind<'tcx> {
         /// practice.
         imaginary_target: BasicBlock,
     },
-    /// A terminator for blocks that only take one path in reality, but where we
-    /// reserve the right to unwind in borrowck, even if it won't happen in practice.
-    /// This can arise in infinite loops with no function calls for example.
+
+    /// A terminator for blocks that only take one path in reality, but where we reserve the right
+    /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops
+    /// with no function calls for example.
+    ///
+    /// At runtime this is semantically just a goto.
+    ///
+    /// Disallowed after drop elaboration.
     FalseUnwind {
         /// The target normal control flow will take.
         real_target: BasicBlock,
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index b31cc17..b17343d 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -19,11 +19,11 @@
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{
-    BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
+    self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
 };
 use rustc_middle::ty::adjustment::PointerCast;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
+use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
 use rustc_middle::ty::{
     CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
 };
@@ -375,7 +375,7 @@ pub enum ExprKind<'tcx> {
     /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
     Repeat {
         value: ExprId,
-        count: Const<'tcx>,
+        count: ty::Const<'tcx>,
     },
     /// An array, e.g. `[a, b, c, d]`.
     Array {
@@ -522,7 +522,7 @@ pub enum InlineAsmOperand<'tcx> {
         out_expr: Option<ExprId>,
     },
     Const {
-        value: Const<'tcx>,
+        value: mir::ConstantKind<'tcx>,
         span: Span,
     },
     SymFn {
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 451fa46..ef7becd 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -24,6 +24,15 @@ fn visit_arm(&mut self, arm: &Arm<'tcx>) {
     fn visit_pat(&mut self, pat: &Pat<'tcx>) {
         walk_pat(self, pat);
     }
+
+    // Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
+    // (even though these types occur in THIR) for consistency and to reduce confusion,
+    // since the lazy creation of constants during thir construction causes most
+    // 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
+    // stage (they are mostly still identified by `DefId` or `hir::Lit`, see
+    // the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
+    // You have to manually visit `ty::Const` and `mir::ConstantKind` through the
+    // other `visit*` functions.
 }
 
 pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index b8da35a..35d286d2 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -126,7 +126,8 @@ pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
     /// return `None`.
-    pub(super) fn try_eval(
+    // FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
+    pub fn try_eval(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 5244aaa..4e6be84 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -47,7 +47,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_macros::HashStable;
 use rustc_middle::mir::FakeReadCause;
-use rustc_query_system::ich::{NodeIdHashingMode, StableHashingContext};
+use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::{BorrowckMode, CrateType, OutputFilenames};
 use rustc_session::lint::{Level, Lint};
@@ -367,7 +367,7 @@ pub struct GeneratorInteriorTypeCause<'tcx> {
     pub expr: Option<hir::HirId>,
 }
 
-#[derive(TyEncodable, TyDecodable, Debug)]
+#[derive(TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct TypeckResults<'tcx> {
     /// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
     pub hir_owner: LocalDefId,
@@ -783,62 +783,6 @@ pub fn coercion_casts(&self) -> &ItemLocalSet {
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let ty::TypeckResults {
-            hir_owner,
-            ref type_dependent_defs,
-            ref field_indices,
-            ref user_provided_types,
-            ref user_provided_sigs,
-            ref node_types,
-            ref node_substs,
-            ref adjustments,
-            ref pat_binding_modes,
-            ref pat_adjustments,
-            ref closure_kind_origins,
-            ref liberated_fn_sigs,
-            ref fru_field_types,
-            ref coercion_casts,
-            ref used_trait_imports,
-            tainted_by_errors,
-            ref concrete_opaque_types,
-            ref closure_min_captures,
-            ref closure_fake_reads,
-            ref generator_interior_types,
-            ref treat_byte_string_as_slice,
-            ref closure_size_eval,
-        } = *self;
-
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            hcx.local_def_path_hash(hir_owner);
-
-            type_dependent_defs.hash_stable(hcx, hasher);
-            field_indices.hash_stable(hcx, hasher);
-            user_provided_types.hash_stable(hcx, hasher);
-            user_provided_sigs.hash_stable(hcx, hasher);
-            node_types.hash_stable(hcx, hasher);
-            node_substs.hash_stable(hcx, hasher);
-            adjustments.hash_stable(hcx, hasher);
-            pat_binding_modes.hash_stable(hcx, hasher);
-            pat_adjustments.hash_stable(hcx, hasher);
-
-            closure_kind_origins.hash_stable(hcx, hasher);
-            liberated_fn_sigs.hash_stable(hcx, hasher);
-            fru_field_types.hash_stable(hcx, hasher);
-            coercion_casts.hash_stable(hcx, hasher);
-            used_trait_imports.hash_stable(hcx, hasher);
-            tainted_by_errors.hash_stable(hcx, hasher);
-            concrete_opaque_types.hash_stable(hcx, hasher);
-            closure_min_captures.hash_stable(hcx, hasher);
-            closure_fake_reads.hash_stable(hcx, hasher);
-            generator_interior_types.hash_stable(hcx, hasher);
-            treat_byte_string_as_slice.hash_stable(hcx, hasher);
-            closure_size_eval.hash_stable(hcx, hasher);
-        })
-    }
-}
-
 rustc_index::newtype_index! {
     pub struct UserTypeAnnotationIndex {
         derive [HashStable]
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 49d0ce5..3b044b1 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -336,10 +336,14 @@ pub fn suggest_constraining_type_params<'a>(
         }
 
         let constraint = constraints.iter().map(|&(c, _)| c).collect::<Vec<_>>().join(" + ");
-        let mut suggest_restrict = |span| {
+        let mut suggest_restrict = |span, bound_list_non_empty| {
             suggestions.push((
                 span,
-                format!(" + {}", constraint),
+                if bound_list_non_empty {
+                    format!(" + {}", constraint)
+                } else {
+                    format!(" {}", constraint)
+                },
                 SuggestChangingConstraintsMessage::RestrictBoundFurther,
             ))
         };
@@ -360,7 +364,10 @@ pub fn suggest_constraining_type_params<'a>(
             //             |
             //             replace with: `impl Foo + Bar`
 
-            suggest_restrict(param.span.shrink_to_hi());
+            // `impl Trait` must have at least one trait in the list
+            let bound_list_non_empty = true;
+
+            suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty);
             continue;
         }
 
@@ -383,15 +390,25 @@ pub fn suggest_constraining_type_params<'a>(
                 //          --
                 //          |
                 //          replace with: `T: Bar +`
-                suggest_restrict(span);
+
+                // `bounds_span_for_suggestions` returns `None` if the list is empty
+                let bound_list_non_empty = true;
+
+                suggest_restrict(span, bound_list_non_empty);
             } else {
+                let (colon, span) = match param.colon_span_for_suggestions(tcx.sess.source_map()) {
+                    // If there is already a colon after generic, do not suggest adding it again
+                    Some(sp) => ("", sp.shrink_to_hi()),
+                    None => (":", param.span.shrink_to_hi()),
+                };
+
                 // If user hasn't provided any bounds, suggest adding a new one:
                 //
                 //   fn foo<T>(t: T) { ... }
                 //          - help: consider restricting this type parameter with `T: Foo`
                 suggestions.push((
-                    param.span.shrink_to_hi(),
-                    format!(": {}", constraint),
+                    span,
+                    format!("{colon} {constraint}"),
                     SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
                 ));
             }
@@ -459,17 +476,21 @@ pub fn suggest_constraining_type_params<'a>(
                 ));
             } else {
                 let mut param_spans = Vec::new();
+                let mut non_empty = false;
 
                 for predicate in generics.where_clause.predicates {
                     if let WherePredicate::BoundPredicate(WhereBoundPredicate {
                         span,
                         bounded_ty,
+                        bounds,
                         ..
                     }) = predicate
                     {
                         if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
                             if let Some(segment) = path.segments.first() {
                                 if segment.ident.to_string() == param_name {
+                                    non_empty = !bounds.is_empty();
+
                                     param_spans.push(span);
                                 }
                             }
@@ -478,7 +499,7 @@ pub fn suggest_constraining_type_params<'a>(
                 }
 
                 match param_spans[..] {
-                    [&param_span] => suggest_restrict(param_span.shrink_to_hi()),
+                    [&param_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty),
                     _ => {
                         suggestions.push((
                             generics.where_clause.tail_span_for_suggestion(),
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index a974971..39038e8 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -18,7 +18,6 @@
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
-use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_span::{sym, DUMMY_SP};
 use rustc_target::abi::{Integer, Size, TargetDataLayout};
 use smallvec::SmallVec;
@@ -136,11 +135,7 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
         // regions, which is desirable too.
         let ty = self.erase_regions(ty);
 
-        hcx.while_hashing_spans(false, |hcx| {
-            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                ty.hash_stable(hcx, &mut hasher);
-            });
-        });
+        hcx.while_hashing_spans(false, |hcx| ty.hash_stable(hcx, &mut hasher));
         hasher.finish()
     }
 
diff --git a/compiler/rustc_mir_build/src/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs
index dca9a63..ac92b03 100644
--- a/compiler/rustc_mir_build/src/build/cfg.rs
+++ b/compiler/rustc_mir_build/src/build/cfg.rs
@@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
             Rvalue::Use(Operand::Constant(Box::new(Constant {
                 span: source_info.span,
                 user_ty: None,
-                literal: ConstantKind::from_zero_sized(tcx.types.unit),
+                literal: ConstantKind::zero_sized(tcx.types.unit),
             }))),
         );
     }
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 6856ded..8b9b184 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -2,11 +2,10 @@
 
 use crate::build::Builder;
 use crate::thir::constant::parse_float;
-use rustc_ast::ast;
+use rustc_ast as ast;
 use rustc_hir::def_id::DefId;
-use rustc_middle::mir::interpret::{
-    Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
-};
+use rustc_middle::mir::interpret::Allocation;
+use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::subst::SubstsRef;
@@ -32,11 +31,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Literal { lit, neg } => {
                 let literal =
-                    match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
+                    match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
                         Ok(c) => c,
                         Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
                         Err(LitToConstError::TypeError) => {
-                            bug!("encountered type error in `lit_to_constant")
+                            bug!("encountered type error in `lit_to_mir_constant")
                         }
                     };
 
@@ -90,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     }
 }
 
-crate fn lit_to_constant<'tcx>(
+#[instrument(skip(tcx, lit_input))]
+fn lit_to_mir_constant<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
 ) -> Result<ConstantKind<'tcx>, LitToConstError> {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 3f8a1a3..be77741 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -322,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
                     span: expr_span,
                     user_ty: None,
-                    literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
+                    literal: ConstantKind::zero_sized(this.tcx.types.unit),
                 }))))
             }
             ExprKind::Yield { .. }
@@ -552,7 +552,7 @@ fn limit_capture_mutability(
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let param_ty = ty::ParamEnv::empty().and(ty);
         let size = self.tcx.layout_of(param_ty).unwrap().size;
-        let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
+        let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
 
         self.literal_operand(span, literal)
     }
@@ -563,7 +563,7 @@ fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         let param_ty = ty::ParamEnv::empty().and(ty);
         let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
         let n = 1 << (bits - 1);
-        let literal = ty::Const::from_bits(self.tcx, n, param_ty);
+        let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 96069f0..806c260 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -264,7 +264,7 @@ pub(super) fn perform_test(
                     );
                 } else if let [success, fail] = *make_target_blocks(self) {
                     assert_eq!(value.ty(), ty);
-                    let expect = self.literal_operand(test.span, value);
+                    let expect = self.literal_operand(test.span, value.into());
                     let val = Operand::Copy(place);
                     self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
                 } else {
@@ -277,8 +277,8 @@ pub(super) fn perform_test(
                 let target_blocks = make_target_blocks(self);
 
                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
-                let lo = self.literal_operand(test.span, lo);
-                let hi = self.literal_operand(test.span, hi);
+                let lo = self.literal_operand(test.span, lo.into());
+                let hi = self.literal_operand(test.span, hi.into());
                 let val = Operand::Copy(place);
 
                 let [success, fail] = *target_blocks else {
@@ -370,7 +370,7 @@ fn non_scalar_compare(
         place: Place<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
-        let mut expect = self.literal_operand(source_info.span, value);
+        let mut expect = self.literal_operand(source_info.span, value.into());
         let mut val = Operand::Copy(place);
 
         // If we're using `b"..."` as a pattern, we need to insert an
@@ -823,7 +823,7 @@ fn trait_method<'tcx>(
     method_name: Symbol,
     self_ty: Ty<'tcx>,
     params: &[GenericArg<'tcx>],
-) -> ty::Const<'tcx> {
+) -> ConstantKind<'tcx> {
     let substs = tcx.mk_substs_trait(self_ty, params);
 
     // The unhygienic comparison here is acceptable because this is only
@@ -836,5 +836,6 @@ fn trait_method<'tcx>(
 
     let method_ty = tcx.type_of(item.def_id);
     let method_ty = method_ty.subst(tcx, substs);
-    ty::Const::zero_sized(tcx, method_ty)
+
+    ConstantKind::zero_sized(method_ty)
 }
diff --git a/compiler/rustc_mir_build/src/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs
index 3516eca..84762d6 100644
--- a/compiler/rustc_mir_build/src/build/misc.rs
+++ b/compiler/rustc_mir_build/src/build/misc.rs
@@ -3,6 +3,7 @@
 
 use crate::build::Builder;
 
+use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{Span, DUMMY_SP};
@@ -25,8 +26,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     /// Convenience function for creating a literal operand, one
     /// without any user type annotation.
-    crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> {
-        let literal = literal.into();
+    crate fn literal_operand(
+        &mut self,
+        span: Span,
+        literal: mir::ConstantKind<'tcx>,
+    ) -> Operand<'tcx> {
         let constant = Box::new(Constant { span, user_ty: None, literal });
         Operand::Constant(constant)
     }
@@ -34,7 +38,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     // Returns a zero literal operand for the appropriate type, works for
     // bool, char and integers.
     crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let literal = ty::Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
+        let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
 
         self.literal_operand(span, literal)
     }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index e6afc89..7ef3301 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -8,7 +8,7 @@
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
-use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
+use rustc_middle::mir::{self, BinOp, BorrowKind, Field, UnOp};
 use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
@@ -491,7 +491,11 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                             hir::InlineAsmOperand::Const { ref anon_const } => {
                                 let anon_const_def_id =
                                     self.tcx.hir().local_def_id(anon_const.hir_id);
-                                let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+                                let value = mir::ConstantKind::from_anon_const(
+                                    self.tcx,
+                                    anon_const_def_id,
+                                    self.param_env,
+                                );
                                 let span = self.tcx.hir().span(anon_const.hir_id);
 
                                 InlineAsmOperand::Const { value, span }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index bb3ba3e..72f0d07 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -55,7 +55,7 @@
 use rustc_middle::mir::Field;
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
 use rustc_middle::ty::layout::IntegerExt;
-use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef};
+use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
 use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
 use rustc_session::lint;
 use rustc_span::{Span, DUMMY_SP};
@@ -136,7 +136,7 @@ fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u
     fn from_const<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: Const<'tcx>,
+        value: ty::Const<'tcx>,
     ) -> Option<IntRange> {
         let ty = value.ty();
         if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
@@ -829,7 +829,8 @@ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self)
                 }
             }
             (Str(self_val), Str(other_val)) => {
-                // FIXME: there's probably a more direct way of comparing for equality
+                // FIXME Once valtrees are available we can directly use the bytes
+                // in the `Str` variant of the valtree for the comparison here.
                 match compare_const_vals(
                     pcx.cx.tcx,
                     *self_val,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 72b597b..dbcd701 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -488,9 +488,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
 
         match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
             Ok(value) => {
-                let const_ =
-                    ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
-
+                let const_ = ty::Const::from_value(self.tcx, value, ty);
                 let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
 
                 if !is_associated_const {
@@ -585,7 +583,7 @@ fn lower_lit(&mut self, expr: &'tcx hir::Expr<'tcx>) -> PatKind<'tcx> {
         let lit_input =
             LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
         match self.tcx.at(expr.span).lit_to_const(lit_input) {
-            Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind,
+            Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
             Err(LitToConstError::Reported) => PatKind::Wild,
             Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
         }
@@ -739,6 +737,7 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     }
 }
 
+#[instrument(skip(tcx), level = "debug")]
 crate fn compare_const_vals<'tcx>(
     tcx: TyCtxt<'tcx>,
     a: ty::Const<'tcx>,
@@ -746,8 +745,6 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ordering> {
-    trace!("compare_const_vals: {:?}, {:?}", a, b);
-
     let from_bool = |v: bool| v.then_some(Ordering::Equal);
 
     let fallback = || from_bool(a == b);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 15bb5ad..687b2e2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -765,10 +765,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
 /// `is_under_guard` is used to inform if the pattern has a guard. If it
 /// has one it must not be inserted into the matrix. This shouldn't be
 /// relied on for soundness.
-#[instrument(
-    level = "debug",
-    skip(cx, matrix, witness_preference, hir_id, is_under_guard, is_top_level)
-)]
+#[instrument(level = "debug", skip(cx, matrix, hir_id))]
 fn is_useful<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     matrix: &Matrix<'p, 'tcx>,
@@ -800,6 +797,7 @@ fn is_useful<'p, 'tcx>(
 
     let ty = v.head().ty();
     let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
+    debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
     let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
 
     // If the first pattern is an or-pattern, expand it.
@@ -809,9 +807,11 @@ fn is_useful<'p, 'tcx>(
         // We try each or-pattern branch in turn.
         let mut matrix = matrix.clone();
         for v in v.expand_or_pat() {
+            debug!(?v);
             let usefulness = ensure_sufficient_stack(|| {
                 is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
             });
+            debug!(?usefulness);
             ret.extend(usefulness);
             // If pattern has a guard don't add it to the matrix.
             if !is_under_guard {
@@ -822,6 +822,7 @@ fn is_useful<'p, 'tcx>(
         }
     } else {
         let v_ctor = v.head().ctor();
+        debug!(?v_ctor);
         if let Constructor::IntRange(ctor_range) = &v_ctor {
             // Lint on likely incorrect range patterns (#63987)
             ctor_range.lint_overlapping_range_endpoints(
@@ -895,7 +896,7 @@ fn is_useful<'p, 'tcx>(
 }
 
 /// The arm of a match expression.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 crate struct MatchArm<'p, 'tcx> {
     /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
     crate pat: &'p DeconstructedPat<'p, 'tcx>,
@@ -928,6 +929,7 @@ fn is_useful<'p, 'tcx>(
 ///
 /// Note: the input patterns must have been lowered through
 /// `check_match::MatchVisitor::lower_pattern`.
+#[instrument(skip(cx, arms), level = "debug")]
 crate fn compute_match_usefulness<'p, 'tcx>(
     cx: &MatchCheckCtxt<'p, 'tcx>,
     arms: &[MatchArm<'p, 'tcx>],
@@ -939,6 +941,7 @@ fn is_useful<'p, 'tcx>(
         .iter()
         .copied()
         .map(|arm| {
+            debug!(?arm);
             let v = PatStack::from_pattern(arm.pat);
             is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true);
             if !arm.has_guard {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 5bf6f22..ca81921 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -970,7 +970,7 @@ fn parse_crate_name_with_dashes(&mut self) -> PResult<'a, Ident> {
         }
         if fixed_crate_name {
             let fixed_name_sp = ident.span.to(idents.last().unwrap().span);
-            let mut fixed_name = format!("{}", ident.name);
+            let mut fixed_name = ident.name.to_string();
             for part in idents {
                 fixed_name.push_str(&format!("_{}", part.name));
             }
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index a073bf7..03ef857 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -2,8 +2,7 @@
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sorted_map::SortedMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::stable_hasher::{HashingControls, NodeIdHashingMode};
+use rustc_data_structures::stable_hasher::{HashStable, HashingControls, StableHasher};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -69,10 +68,7 @@ fn new_with_or_without_spans(
             incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
             caching_source_map: None,
             raw_source_map: sess.source_map(),
-            hashing_controls: HashingControls {
-                hash_spans: hash_spans_initial,
-                node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
-            },
+            hashing_controls: HashingControls { hash_spans: hash_spans_initial },
         }
     }
 
@@ -139,18 +135,6 @@ pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f:
     }
 
     #[inline]
-    pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
-        &mut self,
-        mode: NodeIdHashingMode,
-        f: F,
-    ) {
-        let prev = self.hashing_controls.node_id_hashing_mode;
-        self.hashing_controls.node_id_hashing_mode = mode;
-        f(self);
-        self.hashing_controls.node_id_hashing_mode = prev;
-    }
-
-    #[inline]
     pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
         if let Some(def_id) = def_id.as_local() {
             self.local_def_path_hash(def_id)
@@ -233,9 +217,7 @@ fn hashing_controls(&self) -> HashingControls {
 
 impl<'a> rustc_data_structures::intern::InternedHashingContext for StableHashingContext<'a> {
     fn with_def_path_and_no_spans(&mut self, f: impl FnOnce(&mut Self)) {
-        self.while_hashing_spans(false, |hcx| {
-            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| f(hcx))
-        });
+        self.while_hashing_spans(false, f);
     }
 }
 
diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
index bf3cf6a..3390ed9 100644
--- a/compiler/rustc_query_system/src/ich/impls_hir.rs
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -2,29 +2,12 @@
 //! types in no particular order.
 
 use crate::ich::hcx::BodyResolver;
-use crate::ich::{NodeIdHashingMode, StableHashingContext};
+use crate::ich::StableHashingContext;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
-use std::mem;
 
 impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
     #[inline]
-    fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
-        let hcx = self;
-        match hcx.hashing_controls.node_id_hashing_mode {
-            NodeIdHashingMode::Ignore => {
-                // Don't do anything.
-            }
-            NodeIdHashingMode::HashDefPath => {
-                let hir::HirId { owner, local_id } = hir_id;
-
-                hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
-                local_id.hash_stable(hcx, hasher);
-            }
-        }
-    }
-
-    #[inline]
     fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
         let hcx = self;
         match hcx.body_resolver {
@@ -37,19 +20,11 @@ fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
         }
     }
 
-    #[inline]
-    fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) {
-        let hcx = self;
-
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            id.hash_stable(hcx, hasher);
-        })
-    }
-
     fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
         self.while_hashing_hir_bodies(true, |hcx| {
-            let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
+            let hir::Expr { hir_id, ref span, ref kind } = *expr;
 
+            hir_id.hash_stable(hcx, hasher);
             span.hash_stable(hcx, hasher);
             kind.hash_stable(hcx, hasher);
         })
@@ -57,66 +32,11 @@ fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
 
     fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) {
         self.while_hashing_hir_bodies(true, |hcx| {
-            let hir::Ty { hir_id: _, ref kind, ref span } = *ty;
+            let hir::Ty { hir_id, ref kind, ref span } = *ty;
 
+            hir_id.hash_stable(hcx, hasher);
             kind.hash_stable(hcx, hasher);
             span.hash_stable(hcx, hasher);
         })
     }
-
-    fn hash_hir_visibility_kind(
-        &mut self,
-        vis: &hir::VisibilityKind<'_>,
-        hasher: &mut StableHasher,
-    ) {
-        let hcx = self;
-        mem::discriminant(vis).hash_stable(hcx, hasher);
-        match *vis {
-            hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => {
-                // No fields to hash.
-            }
-            hir::VisibilityKind::Crate(sugar) => {
-                sugar.hash_stable(hcx, hasher);
-            }
-            hir::VisibilityKind::Restricted { ref path, hir_id } => {
-                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                    hir_id.hash_stable(hcx, hasher);
-                });
-                path.hash_stable(hcx, hasher);
-            }
-        }
-    }
-
-    #[inline]
-    fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
-        let prev_hash_node_ids = self.hashing_controls.node_id_hashing_mode;
-        self.hashing_controls.node_id_hashing_mode = NodeIdHashingMode::Ignore;
-
-        f(self);
-
-        self.hashing_controls.node_id_hashing_mode = prev_hash_node_ids;
-    }
-
-    #[inline]
-    fn hash_hir_trait_candidate(&mut self, tc: &hir::TraitCandidate, hasher: &mut StableHasher) {
-        self.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-            let hir::TraitCandidate { def_id, import_ids } = tc;
-
-            def_id.hash_stable(hcx, hasher);
-            import_ids.hash_stable(hcx, hasher);
-        });
-    }
-}
-
-impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let hir::Body { params, value, generator_kind } = self;
-
-        hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| {
-            params.hash_stable(hcx, hasher);
-            value.hash_stable(hcx, hasher);
-            generator_kind.hash_stable(hcx, hasher);
-        });
-    }
 }
diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
index c42fcc9..0a1c350 100644
--- a/compiler/rustc_query_system/src/ich/mod.rs
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -1,7 +1,6 @@
 //! ICH - Incremental Compilation Hash
 
 pub use self::hcx::StableHashingContext;
-pub use rustc_data_structures::stable_hasher::NodeIdHashingMode;
 use rustc_span::symbol::{sym, Symbol};
 
 mod hcx;
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 07d261d..54e8c03 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -297,6 +297,7 @@ fn try_resolve_visibility<'ast>(
                     Some(TypeNS),
                     parent_scope,
                     if finalize { Finalize::SimplePath(id, path.span) } else { Finalize::No },
+                    None,
                 ) {
                     PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
                         let res = module.res().expect("visibility resolved to unnamed block");
@@ -1124,12 +1125,11 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool
             });
         } else {
             for ident in single_imports.iter().cloned() {
-                let result = self.r.resolve_ident_in_module(
+                let result = self.r.maybe_resolve_ident_in_module(
                     ModuleOrUniformRoot::Module(module),
                     ident,
                     MacroNS,
                     &self.parent_scope,
-                    None,
                 );
                 if let Ok(binding) = result {
                     let import = macro_use_import(self, ident.span);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 609dbd1f..d979311 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1,19 +1,24 @@
 use std::ptr;
 
-use rustc_ast::{self as ast, Path};
+use rustc_ast::ptr::P;
+use rustc_ast::visit::{self, Visitor};
+use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{
-    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
-};
+use rustc_errors::struct_span_err;
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::PrimTy;
 use rustc_middle::bug;
 use rustc_middle::ty::DefIdTree;
+use rustc_session::lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE;
+use rustc_session::lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS;
+use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::Session;
+use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::lev_distance::find_best_match_for_name;
 use rustc_span::source_map::SourceMap;
@@ -22,11 +27,13 @@
 use tracing::debug;
 
 use crate::imports::{Import, ImportKind, ImportResolver};
+use crate::late::Rib;
 use crate::path_names_to_string;
-use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
-use crate::{BindingError, HasGenericParams, MacroRulesScope, Module, ModuleOrUniformRoot};
-use crate::{Finalize, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
-use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet, Segment};
+use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
+use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
+use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
+use crate::{Segment, UseError};
 
 type Res = def::Res<ast::NodeId>;
 
@@ -82,6 +89,390 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
 }
 
 impl<'a> Resolver<'a> {
+    crate fn report_errors(&mut self, krate: &Crate) {
+        self.report_with_use_injections(krate);
+
+        for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
+            let msg = "macro-expanded `macro_export` macros from the current crate \
+                       cannot be referred to by absolute paths";
+            self.lint_buffer.buffer_lint_with_diagnostic(
+                MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+                CRATE_NODE_ID,
+                span_use,
+                msg,
+                BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
+            );
+        }
+
+        for ambiguity_error in &self.ambiguity_errors {
+            self.report_ambiguity_error(ambiguity_error);
+        }
+
+        let mut reported_spans = FxHashSet::default();
+        for error in &self.privacy_errors {
+            if reported_spans.insert(error.dedup_span) {
+                self.report_privacy_error(error);
+            }
+        }
+    }
+
+    fn report_with_use_injections(&mut self, krate: &Crate) {
+        for UseError { mut err, candidates, def_id, instead, suggestion } in
+            self.use_injections.drain(..)
+        {
+            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
+                UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
+            } else {
+                (None, false)
+            };
+            if !candidates.is_empty() {
+                show_candidates(
+                    &self.definitions,
+                    self.session,
+                    &mut err,
+                    span,
+                    &candidates,
+                    instead,
+                    found_use,
+                );
+            } else if let Some((span, msg, sugg, appl)) = suggestion {
+                err.span_suggestion(span, msg, sugg, appl);
+            }
+            err.emit();
+        }
+    }
+
+    crate fn report_conflict<'b>(
+        &mut self,
+        parent: Module<'_>,
+        ident: Ident,
+        ns: Namespace,
+        new_binding: &NameBinding<'b>,
+        old_binding: &NameBinding<'b>,
+    ) {
+        // Error on the second of two conflicting names
+        if old_binding.span.lo() > new_binding.span.lo() {
+            return self.report_conflict(parent, ident, ns, old_binding, new_binding);
+        }
+
+        let container = match parent.kind {
+            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
+            ModuleKind::Block(..) => "block",
+        };
+
+        let old_noun = match old_binding.is_import() {
+            true => "import",
+            false => "definition",
+        };
+
+        let new_participle = match new_binding.is_import() {
+            true => "imported",
+            false => "defined",
+        };
+
+        let (name, span) =
+            (ident.name, self.session.source_map().guess_head_span(new_binding.span));
+
+        if let Some(s) = self.name_already_seen.get(&name) {
+            if s == &span {
+                return;
+            }
+        }
+
+        let old_kind = match (ns, old_binding.module()) {
+            (ValueNS, _) => "value",
+            (MacroNS, _) => "macro",
+            (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
+            (TypeNS, Some(module)) if module.is_normal() => "module",
+            (TypeNS, Some(module)) if module.is_trait() => "trait",
+            (TypeNS, _) => "type",
+        };
+
+        let msg = format!("the name `{}` is defined multiple times", name);
+
+        let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
+            (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
+            (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
+                true => struct_span_err!(self.session, span, E0254, "{}", msg),
+                false => struct_span_err!(self.session, span, E0260, "{}", msg),
+            },
+            _ => match (old_binding.is_import(), new_binding.is_import()) {
+                (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
+                (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
+                _ => struct_span_err!(self.session, span, E0255, "{}", msg),
+            },
+        };
+
+        err.note(&format!(
+            "`{}` must be defined only once in the {} namespace of this {}",
+            name,
+            ns.descr(),
+            container
+        ));
+
+        err.span_label(span, format!("`{}` re{} here", name, new_participle));
+        err.span_label(
+            self.session.source_map().guess_head_span(old_binding.span),
+            format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
+        );
+
+        // See https://github.com/rust-lang/rust/issues/32354
+        use NameBindingKind::Import;
+        let import = match (&new_binding.kind, &old_binding.kind) {
+            // If there are two imports where one or both have attributes then prefer removing the
+            // import without attributes.
+            (Import { import: new, .. }, Import { import: old, .. })
+                if {
+                    !new_binding.span.is_dummy()
+                        && !old_binding.span.is_dummy()
+                        && (new.has_attributes || old.has_attributes)
+                } =>
+            {
+                if old.has_attributes {
+                    Some((new, new_binding.span, true))
+                } else {
+                    Some((old, old_binding.span, true))
+                }
+            }
+            // Otherwise prioritize the new binding.
+            (Import { import, .. }, other) if !new_binding.span.is_dummy() => {
+                Some((import, new_binding.span, other.is_import()))
+            }
+            (other, Import { import, .. }) if !old_binding.span.is_dummy() => {
+                Some((import, old_binding.span, other.is_import()))
+            }
+            _ => None,
+        };
+
+        // Check if the target of the use for both bindings is the same.
+        let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
+        let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
+        let from_item =
+            self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
+        // Only suggest removing an import if both bindings are to the same def, if both spans
+        // aren't dummy spans. Further, if both bindings are imports, then the ident must have
+        // been introduced by an item.
+        let should_remove_import = duplicate
+            && !has_dummy_span
+            && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
+
+        match import {
+            Some((import, span, true)) if should_remove_import && import.is_nested() => {
+                self.add_suggestion_for_duplicate_nested_use(&mut err, import, span)
+            }
+            Some((import, _, true)) if should_remove_import && !import.is_glob() => {
+                // Simple case - remove the entire import. Due to the above match arm, this can
+                // only be a single use so just remove it entirely.
+                err.tool_only_span_suggestion(
+                    import.use_span_with_attributes,
+                    "remove unnecessary import",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            Some((import, span, _)) => {
+                self.add_suggestion_for_rename_of_use(&mut err, name, import, span)
+            }
+            _ => {}
+        }
+
+        err.emit();
+        self.name_already_seen.insert(name, span);
+    }
+
+    /// This function adds a suggestion to change the binding name of a new import that conflicts
+    /// with an existing import.
+    ///
+    /// ```text,ignore (diagnostic)
+    /// help: you can use `as` to change the binding name of the import
+    ///    |
+    /// LL | use foo::bar as other_bar;
+    ///    |     ^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    fn add_suggestion_for_rename_of_use(
+        &self,
+        err: &mut Diagnostic,
+        name: Symbol,
+        import: &Import<'_>,
+        binding_span: Span,
+    ) {
+        let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
+            format!("Other{}", name)
+        } else {
+            format!("other_{}", name)
+        };
+
+        let mut suggestion = None;
+        match import.kind {
+            ImportKind::Single { type_ns_only: true, .. } => {
+                suggestion = Some(format!("self as {}", suggested_name))
+            }
+            ImportKind::Single { source, .. } => {
+                if let Some(pos) =
+                    source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
+                {
+                    if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) {
+                        if pos <= snippet.len() {
+                            suggestion = Some(format!(
+                                "{} as {}{}",
+                                &snippet[..pos],
+                                suggested_name,
+                                if snippet.ends_with(';') { ";" } else { "" }
+                            ))
+                        }
+                    }
+                }
+            }
+            ImportKind::ExternCrate { source, target } => {
+                suggestion = Some(format!(
+                    "extern crate {} as {};",
+                    source.unwrap_or(target.name),
+                    suggested_name,
+                ))
+            }
+            _ => unreachable!(),
+        }
+
+        let rename_msg = "you can use `as` to change the binding name of the import";
+        if let Some(suggestion) = suggestion {
+            err.span_suggestion(
+                binding_span,
+                rename_msg,
+                suggestion,
+                Applicability::MaybeIncorrect,
+            );
+        } else {
+            err.span_label(binding_span, rename_msg);
+        }
+    }
+
+    /// This function adds a suggestion to remove an unnecessary binding from an import that is
+    /// nested. In the following example, this function will be invoked to remove the `a` binding
+    /// in the second use statement:
+    ///
+    /// ```ignore (diagnostic)
+    /// use issue_52891::a;
+    /// use issue_52891::{d, a, e};
+    /// ```
+    ///
+    /// The following suggestion will be added:
+    ///
+    /// ```ignore (diagnostic)
+    /// use issue_52891::{d, a, e};
+    ///                      ^-- help: remove unnecessary import
+    /// ```
+    ///
+    /// If the nested use contains only one import then the suggestion will remove the entire
+    /// line.
+    ///
+    /// It is expected that the provided import is nested - this isn't checked by the
+    /// function. If this invariant is not upheld, this function's behaviour will be unexpected
+    /// as characters expected by span manipulations won't be present.
+    fn add_suggestion_for_duplicate_nested_use(
+        &self,
+        err: &mut Diagnostic,
+        import: &Import<'_>,
+        binding_span: Span,
+    ) {
+        assert!(import.is_nested());
+        let message = "remove unnecessary import";
+
+        // Two examples will be used to illustrate the span manipulations we're doing:
+        //
+        // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
+        //   `a` and `import.use_span` is `issue_52891::{d, a, e};`.
+        // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
+        //   `a` and `import.use_span` is `issue_52891::{d, e, a};`.
+
+        let (found_closing_brace, span) =
+            find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span);
+
+        // If there was a closing brace then identify the span to remove any trailing commas from
+        // previous imports.
+        if found_closing_brace {
+            if let Some(span) = extend_span_to_previous_binding(self.session, span) {
+                err.tool_only_span_suggestion(
+                    span,
+                    message,
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            } else {
+                // Remove the entire line if we cannot extend the span back, this indicates an
+                // `issue_52891::{self}` case.
+                err.span_suggestion(
+                    import.use_span_with_attributes,
+                    message,
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+
+            return;
+        }
+
+        err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable);
+    }
+
+    crate fn lint_if_path_starts_with_module(
+        &mut self,
+        finalize: Finalize,
+        path: &[Segment],
+        second_binding: Option<&NameBinding<'_>>,
+    ) {
+        let (diag_id, diag_span) = match finalize {
+            Finalize::No => return,
+            Finalize::SimplePath(id, path_span) => (id, path_span),
+            Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span),
+            Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span),
+        };
+
+        let first_name = match path.get(0) {
+            // In the 2018 edition this lint is a hard error, so nothing to do
+            Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name,
+            _ => return,
+        };
+
+        // We're only interested in `use` paths which should start with
+        // `{{root}}` currently.
+        if first_name != kw::PathRoot {
+            return;
+        }
+
+        match path.get(1) {
+            // If this import looks like `crate::...` it's already good
+            Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
+            // Otherwise go below to see if it's an extern crate
+            Some(_) => {}
+            // If the path has length one (and it's `PathRoot` most likely)
+            // then we don't know whether we're gonna be importing a crate or an
+            // item in our crate. Defer this lint to elsewhere
+            None => return,
+        }
+
+        // If the first element of our path was actually resolved to an
+        // `ExternCrate` (also used for `crate::...`) then no need to issue a
+        // warning, this looks all good!
+        if let Some(binding) = second_binding {
+            if let NameBindingKind::Import { import, .. } = binding.kind {
+                // Careful: we still want to rewrite paths from renamed extern crates.
+                if let ImportKind::ExternCrate { source: None, .. } = import.kind {
+                    return;
+                }
+            }
+        }
+
+        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
+        self.lint_buffer.buffer_lint_with_diagnostic(
+            ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
+            diag_id,
+            diag_span,
+            "absolute paths must start with `self`, `super`, \
+             `crate`, or an external crate name in the 2018 edition",
+            diag,
+        );
+    }
+
     crate fn add_module_candidates(
         &mut self,
         module: Module<'a>,
@@ -632,7 +1023,7 @@ impl<'a> Resolver<'a> {
             VisResolutionError::Relative2018(span, path) => {
                 let mut err = self.session.struct_span_err(
                     span,
-                    "relative paths are not supported in visibilities on 2018 edition",
+                    "relative paths are not supported in visibilities in 2018 edition or later",
                 );
                 err.span_suggestion(
                     path.span,
@@ -1076,6 +1467,8 @@ fn lookup_import_candidates_from_module<FilterFn>(
                 &parent_scope,
                 None,
                 false,
+                false,
+                None,
             ) {
                 let desc = match binding.res() {
                     Res::Def(DefKind::Macro(MacroKind::Bang), _) => {
@@ -1223,7 +1616,7 @@ fn binding_description(&self, b: &NameBinding<'_>, ident: Ident, from_prelude: b
         }
     }
 
-    crate fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
+    fn report_ambiguity_error(&self, ambiguity_error: &AmbiguityError<'_>) {
         let AmbiguityError { kind, ident, b1, b2, misc1, misc2 } = *ambiguity_error;
         let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
             // We have to print the span-less alternative first, otherwise formatting looks bad.
@@ -1289,7 +1682,7 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
         None
     }
 
-    crate fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
+    fn report_privacy_error(&self, privacy_error: &PrivacyError<'_>) {
         let PrivacyError { ident, binding, .. } = *privacy_error;
 
         let res = binding.res();
@@ -1375,6 +1768,188 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
             sugg => sugg,
         }
     }
+
+    crate fn report_path_resolution_error(
+        &mut self,
+        path: &[Segment],
+        opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        parent_scope: &ParentScope<'a>,
+        ribs: Option<&PerNS<Vec<Rib<'a>>>>,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+        module: Option<ModuleOrUniformRoot<'a>>,
+        i: usize,
+        ident: Ident,
+    ) -> (String, Option<Suggestion>) {
+        let is_last = i == path.len() - 1;
+        let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
+        let module_res = match module {
+            Some(ModuleOrUniformRoot::Module(module)) => module.res(),
+            _ => None,
+        };
+        if module_res == self.graph_root.res() {
+            let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
+            let mut candidates = self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
+            candidates
+                .sort_by_cached_key(|c| (c.path.segments.len(), pprust::path_to_string(&c.path)));
+            if let Some(candidate) = candidates.get(0) {
+                (
+                    String::from("unresolved import"),
+                    Some((
+                        vec![(ident.span, pprust::path_to_string(&candidate.path))],
+                        String::from("a similar path exists"),
+                        Applicability::MaybeIncorrect,
+                    )),
+                )
+            } else if self.session.edition() == Edition::Edition2015 {
+                (format!("maybe a missing crate `{}`?", ident), None)
+            } else {
+                (format!("could not find `{}` in the crate root", ident), None)
+            }
+        } else if i > 0 {
+            let parent = path[i - 1].ident.name;
+            let parent = match parent {
+                // ::foo is mounted at the crate root for 2015, and is the extern
+                // prelude for 2018+
+                kw::PathRoot if self.session.edition() > Edition::Edition2015 => {
+                    "the list of imported crates".to_owned()
+                }
+                kw::PathRoot | kw::Crate => "the crate root".to_owned(),
+                _ => format!("`{}`", parent),
+            };
+
+            let mut msg = format!("could not find `{}` in {}", ident, parent);
+            if ns == TypeNS || ns == ValueNS {
+                let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
+                let binding = if let Some(module) = module {
+                    self.resolve_ident_in_module(
+                        module,
+                        ident,
+                        ns_to_try,
+                        parent_scope,
+                        None,
+                        false,
+                        unusable_binding,
+                    ).ok()
+                } else if let Some(ribs) = ribs
+                    && let Some(TypeNS | ValueNS) = opt_ns
+                {
+                    match self.resolve_ident_in_lexical_scope(
+                        ident,
+                        ns_to_try,
+                        parent_scope,
+                        Finalize::No,
+                        &ribs[ns_to_try],
+                        unusable_binding,
+                    ) {
+                        // we found a locally-imported or available item/module
+                        Some(LexicalScopeBinding::Item(binding)) => Some(binding),
+                        _ => None,
+                    }
+                } else {
+                    let scopes = ScopeSet::All(ns_to_try, opt_ns.is_none());
+                    self.early_resolve_ident_in_lexical_scope(
+                        ident,
+                        scopes,
+                        parent_scope,
+                        None,
+                        false,
+                        false,
+                        unusable_binding,
+                    ).ok()
+                };
+                if let Some(binding) = binding {
+                    let mut found = |what| {
+                        msg = format!(
+                            "expected {}, found {} `{}` in {}",
+                            ns.descr(),
+                            what,
+                            ident,
+                            parent
+                        )
+                    };
+                    if binding.module().is_some() {
+                        found("module")
+                    } else {
+                        match binding.res() {
+                            Res::Def(kind, id) => found(kind.descr(id)),
+                            _ => found(ns_to_try.descr()),
+                        }
+                    }
+                };
+            }
+            (msg, None)
+        } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) {
+            // Check whether the name refers to an item in the value namespace.
+            let binding = if let Some(ribs) = ribs {
+                self.resolve_ident_in_lexical_scope(
+                    ident,
+                    ValueNS,
+                    parent_scope,
+                    Finalize::No,
+                    &ribs[ValueNS],
+                    unusable_binding,
+                )
+            } else {
+                None
+            };
+            let match_span = match binding {
+                // Name matches a local variable. For example:
+                // ```
+                // fn f() {
+                //     let Foo: &str = "";
+                //     println!("{}", Foo::Bar); // Name refers to local
+                //                               // variable `Foo`.
+                // }
+                // ```
+                Some(LexicalScopeBinding::Res(Res::Local(id))) => {
+                    Some(*self.pat_span_map.get(&id).unwrap())
+                }
+                // Name matches item from a local name binding
+                // created by `use` declaration. For example:
+                // ```
+                // pub Foo: &str = "";
+                //
+                // mod submod {
+                //     use super::Foo;
+                //     println!("{}", Foo::Bar); // Name refers to local
+                //                               // binding `Foo`.
+                // }
+                // ```
+                Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
+                _ => None,
+            };
+            let suggestion = if let Some(span) = match_span {
+                Some((
+                    vec![(span, String::from(""))],
+                    format!("`{}` is defined here, but is not a type", ident),
+                    Applicability::MaybeIncorrect,
+                ))
+            } else {
+                None
+            };
+
+            (format!("use of undeclared type `{}`", ident), suggestion)
+        } else {
+            let suggestion = if ident.name == sym::alloc {
+                Some((
+                    vec![],
+                    String::from("add `extern crate alloc` to use the `alloc` crate"),
+                    Applicability::MaybeIncorrect,
+                ))
+            } else {
+                self.find_similarly_named_module_or_crate(ident.name, &parent_scope.module).map(
+                    |sugg| {
+                        (
+                            vec![(ident.span, sugg.to_string())],
+                            String::from("there is a crate or module with a similar name"),
+                            Applicability::MaybeIncorrect,
+                        )
+                    },
+                )
+            };
+            (format!("use of undeclared crate or module `{}`", ident), suggestion)
+        }
+    }
 }
 
 impl<'a, 'b> ImportResolver<'a, 'b> {
@@ -1422,7 +1997,7 @@ fn make_missing_self_suggestion(
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `self` and check if that is valid.
         path[0].ident.name = kw::SelfLower;
-        let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No);
+        let result = self.r.maybe_resolve_path(&path, None, parent_scope);
         debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None }
     }
@@ -1441,7 +2016,7 @@ fn make_missing_crate_suggestion(
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Crate;
-        let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No);
+        let result = self.r.maybe_resolve_path(&path, None, parent_scope);
         debug!("make_missing_crate_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result {
             Some((
@@ -1472,7 +2047,7 @@ fn make_missing_super_suggestion(
     ) -> Option<(Vec<Segment>, Vec<String>)> {
         // Replace first ident with `crate` and check if that is valid.
         path[0].ident.name = kw::Super;
-        let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No);
+        let result = self.r.maybe_resolve_path(&path, None, parent_scope);
         debug!("make_missing_super_suggestion:  path={:?} result={:?}", path, result);
         if let PathResult::Module(..) = result { Some((path, Vec::new())) } else { None }
     }
@@ -1506,7 +2081,7 @@ fn make_external_crate_suggestion(
         for name in extern_crate_names.into_iter() {
             // Replace first ident with a crate name and check if that is valid.
             path[0].ident.name = name;
-            let result = self.r.resolve_path(&path, None, parent_scope, Finalize::No);
+            let result = self.r.maybe_resolve_path(&path, None, parent_scope);
             debug!(
                 "make_external_crate_suggestion: name={:?} path={:?} result={:?}",
                 name, path, result
@@ -1673,7 +2248,7 @@ pub(crate) fn check_for_module_export_macro(
 /// use foo::{a, b, c};
 ///              ^^^
 /// ```
-pub(crate) fn find_span_of_binding_until_next_binding(
+fn find_span_of_binding_until_next_binding(
     sess: &Session,
     binding_span: Span,
     use_span: Span,
@@ -1724,7 +2299,7 @@ pub(crate) fn find_span_of_binding_until_next_binding(
 /// use foo::{a, b, c};
 ///           --- binding span
 /// ```
-pub(crate) fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
+fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option<Span> {
     let source_map = sess.source_map();
 
     // `prev_source` will contain all of the source that came before the span.
@@ -1812,7 +2387,7 @@ fn find_span_immediately_after_crate_name(
 /// When an entity with a given name is not available in scope, we search for
 /// entities with that name in all crates. This method allows outputting the
 /// results of this search in a programmer-friendly way
-crate fn show_candidates(
+fn show_candidates(
     definitions: &rustc_hir::definitions::Definitions,
     session: &Session,
     err: &mut Diagnostic,
@@ -1947,3 +2522,70 @@ fn find_span_immediately_after_crate_name(
         }
     }
 }
+
+#[derive(Debug)]
+struct UsePlacementFinder {
+    target_module: NodeId,
+    first_legal_span: Option<Span>,
+    first_use_span: Option<Span>,
+}
+
+impl UsePlacementFinder {
+    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
+        let mut finder =
+            UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
+        finder.visit_crate(krate);
+        if let Some(use_span) = finder.first_use_span {
+            (Some(use_span), true)
+        } else {
+            (finder.first_legal_span, false)
+        }
+    }
+}
+
+impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder {
+    fn visit_crate(&mut self, c: &Crate) {
+        if self.target_module == CRATE_NODE_ID {
+            let inject = c.spans.inject_use_span;
+            if is_span_suitable_for_use_injection(inject) {
+                self.first_legal_span = Some(inject);
+            }
+            self.first_use_span = search_for_any_use_in_items(&c.items);
+            return;
+        } else {
+            visit::walk_crate(self, c);
+        }
+    }
+
+    fn visit_item(&mut self, item: &'tcx ast::Item) {
+        if self.target_module == item.id {
+            if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
+                let inject = mod_spans.inject_use_span;
+                if is_span_suitable_for_use_injection(inject) {
+                    self.first_legal_span = Some(inject);
+                }
+                self.first_use_span = search_for_any_use_in_items(items);
+                return;
+            }
+        } else {
+            visit::walk_item(self, item);
+        }
+    }
+}
+
+fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
+    for item in items {
+        if let ItemKind::Use(..) = item.kind {
+            if is_span_suitable_for_use_injection(item.span) {
+                return Some(item.span.shrink_to_lo());
+            }
+        }
+    }
+    return None;
+}
+
+fn is_span_suitable_for_use_injection(s: Span) -> bool {
+    // don't suggest placing a use before the prelude
+    // import or other generated ones
+    !s.from_expansion()
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
new file mode 100644
index 0000000..25ab3f7
--- /dev/null
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -0,0 +1,1582 @@
+use rustc_ast::{self as ast, NodeId};
+use rustc_feature::is_builtin_attr_name;
+use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
+use rustc_hir::PrimTy;
+use rustc_middle::bug;
+use rustc_middle::ty;
+use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
+use rustc_session::lint::BuiltinLintDiagnostics;
+use rustc_span::edition::Edition;
+use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
+use rustc_span::symbol::{kw, Ident};
+use rustc_span::{Span, DUMMY_SP};
+
+use std::ptr;
+
+use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind};
+use crate::macros::{sub_namespace_match, MacroRulesScope};
+use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
+use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
+use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
+
+use Determinacy::*;
+use Namespace::*;
+use RibKind::*;
+
+impl<'a> Resolver<'a> {
+    /// A generic scope visitor.
+    /// Visits scopes in order to resolve some identifier in them or perform other actions.
+    /// If the callback returns `Some` result, we stop visiting scopes and return it.
+    crate fn visit_scopes<T>(
+        &mut self,
+        scope_set: ScopeSet<'a>,
+        parent_scope: &ParentScope<'a>,
+        ctxt: SyntaxContext,
+        mut visitor: impl FnMut(
+            &mut Self,
+            Scope<'a>,
+            /*use_prelude*/ bool,
+            SyntaxContext,
+        ) -> Option<T>,
+    ) -> Option<T> {
+        // General principles:
+        // 1. Not controlled (user-defined) names should have higher priority than controlled names
+        //    built into the language or standard library. This way we can add new names into the
+        //    language or standard library without breaking user code.
+        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
+        // Places to search (in order of decreasing priority):
+        // (Type NS)
+        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Extern prelude (open, the open part is from macro expansions, not controlled).
+        // 4. Tool modules (closed, controlled right now, but not in the future).
+        // 5. Standard library prelude (de-facto closed, controlled).
+        // 6. Language prelude (closed, controlled).
+        // (Value NS)
+        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Standard library prelude (de-facto closed, controlled).
+        // (Macro NS)
+        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
+        //    are currently reported as errors. They should be higher in priority than preludes
+        //    and probably even names in modules according to the "general principles" above. They
+        //    also should be subject to restricted shadowing because are effectively produced by
+        //    derives (you need to resolve the derive first to add helpers into scope), but they
+        //    should be available before the derive is expanded for compatibility.
+        //    It's mess in general, so we are being conservative for now.
+        // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher
+        //    priority than prelude macros, but create ambiguities with macros in modules.
+        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled). Have higher priority than prelude macros, but create
+        //    ambiguities with `macro_rules`.
+        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
+        // 4a. User-defined prelude from macro-use
+        //    (open, the open part is from macro expansions, not controlled).
+        // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled).
+        // 4c. Standard library prelude (de-facto closed, controlled).
+        // 6. Language prelude: builtin attributes (closed, controlled).
+
+        let rust_2015 = ctxt.edition() == Edition::Edition2015;
+        let (ns, macro_kind, is_absolute_path) = match scope_set {
+            ScopeSet::All(ns, _) => (ns, None, false),
+            ScopeSet::AbsolutePath(ns) => (ns, None, true),
+            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
+            ScopeSet::Late(ns, ..) => (ns, None, false),
+        };
+        let module = match scope_set {
+            // Start with the specified module.
+            ScopeSet::Late(_, module, _) => module,
+            // Jump out of trait or enum modules, they do not act as scopes.
+            _ => parent_scope.module.nearest_item_scope(),
+        };
+        let mut scope = match ns {
+            _ if is_absolute_path => Scope::CrateRoot,
+            TypeNS | ValueNS => Scope::Module(module, None),
+            MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
+        };
+        let mut ctxt = ctxt.normalize_to_macros_2_0();
+        let mut use_prelude = !module.no_implicit_prelude;
+
+        loop {
+            let visit = match scope {
+                // Derive helpers are not in scope when resolving derives in the same container.
+                Scope::DeriveHelpers(expn_id) => {
+                    !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive))
+                }
+                Scope::DeriveHelpersCompat => true,
+                Scope::MacroRules(macro_rules_scope) => {
+                    // Use "path compression" on `macro_rules` scope chains. This is an optimization
+                    // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
+                    // As another consequence of this optimization visitors never observe invocation
+                    // scopes for macros that were already expanded.
+                    while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() {
+                        if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) {
+                            macro_rules_scope.set(next_scope.get());
+                        } else {
+                            break;
+                        }
+                    }
+                    true
+                }
+                Scope::CrateRoot => true,
+                Scope::Module(..) => true,
+                Scope::RegisteredAttrs => use_prelude,
+                Scope::MacroUsePrelude => use_prelude || rust_2015,
+                Scope::BuiltinAttrs => true,
+                Scope::ExternPrelude => use_prelude || is_absolute_path,
+                Scope::ToolPrelude => use_prelude,
+                Scope::StdLibPrelude => use_prelude || ns == MacroNS,
+                Scope::BuiltinTypes => true,
+            };
+
+            if visit {
+                if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) {
+                    return break_result;
+                }
+            }
+
+            scope = match scope {
+                Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat,
+                Scope::DeriveHelpers(expn_id) => {
+                    // Derive helpers are not visible to code generated by bang or derive macros.
+                    let expn_data = expn_id.expn_data();
+                    match expn_data.kind {
+                        ExpnKind::Root
+                        | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
+                            Scope::DeriveHelpersCompat
+                        }
+                        _ => Scope::DeriveHelpers(expn_data.parent.expect_local()),
+                    }
+                }
+                Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules),
+                Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
+                    MacroRulesScope::Binding(binding) => {
+                        Scope::MacroRules(binding.parent_macro_rules_scope)
+                    }
+                    MacroRulesScope::Invocation(invoc_id) => {
+                        Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
+                    }
+                    MacroRulesScope::Empty => Scope::Module(module, None),
+                },
+                Scope::CrateRoot => match ns {
+                    TypeNS => {
+                        ctxt.adjust(ExpnId::root());
+                        Scope::ExternPrelude
+                    }
+                    ValueNS | MacroNS => break,
+                },
+                Scope::Module(module, prev_lint_id) => {
+                    use_prelude = !module.no_implicit_prelude;
+                    let derive_fallback_lint_id = match scope_set {
+                        ScopeSet::Late(.., lint_id) => lint_id,
+                        _ => None,
+                    };
+                    match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
+                        Some((parent_module, lint_id)) => {
+                            Scope::Module(parent_module, lint_id.or(prev_lint_id))
+                        }
+                        None => {
+                            ctxt.adjust(ExpnId::root());
+                            match ns {
+                                TypeNS => Scope::ExternPrelude,
+                                ValueNS => Scope::StdLibPrelude,
+                                MacroNS => Scope::RegisteredAttrs,
+                            }
+                        }
+                    }
+                }
+                Scope::RegisteredAttrs => Scope::MacroUsePrelude,
+                Scope::MacroUsePrelude => Scope::StdLibPrelude,
+                Scope::BuiltinAttrs => break, // nowhere else to search
+                Scope::ExternPrelude if is_absolute_path => break,
+                Scope::ExternPrelude => Scope::ToolPrelude,
+                Scope::ToolPrelude => Scope::StdLibPrelude,
+                Scope::StdLibPrelude => match ns {
+                    TypeNS => Scope::BuiltinTypes,
+                    ValueNS => break, // nowhere else to search
+                    MacroNS => Scope::BuiltinAttrs,
+                },
+                Scope::BuiltinTypes => break, // nowhere else to search
+            };
+        }
+
+        None
+    }
+
+    fn hygienic_lexical_parent(
+        &mut self,
+        module: Module<'a>,
+        ctxt: &mut SyntaxContext,
+        derive_fallback_lint_id: Option<NodeId>,
+    ) -> Option<(Module<'a>, Option<NodeId>)> {
+        if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
+            return Some((self.expn_def_scope(ctxt.remove_mark()), None));
+        }
+
+        if let ModuleKind::Block(..) = module.kind {
+            return Some((module.parent.unwrap().nearest_item_scope(), None));
+        }
+
+        // We need to support the next case under a deprecation warning
+        // ```
+        // struct MyStruct;
+        // ---- begin: this comes from a proc macro derive
+        // mod implementation_details {
+        //     // Note that `MyStruct` is not in scope here.
+        //     impl SomeTrait for MyStruct { ... }
+        // }
+        // ---- end
+        // ```
+        // So we have to fall back to the module's parent during lexical resolution in this case.
+        if derive_fallback_lint_id.is_some() {
+            if let Some(parent) = module.parent {
+                // Inner module is inside the macro, parent module is outside of the macro.
+                if module.expansion != parent.expansion
+                    && module.expansion.is_descendant_of(parent.expansion)
+                {
+                    // The macro is a proc macro derive
+                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
+                        let ext = self.get_macro_by_def_id(def_id);
+                        if ext.builtin_name.is_none()
+                            && ext.macro_kind() == MacroKind::Derive
+                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
+                        {
+                            return Some((parent, derive_fallback_lint_id));
+                        }
+                    }
+                }
+            }
+        }
+
+        None
+    }
+
+    /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
+    /// More specifically, we proceed up the hierarchy of scopes and return the binding for
+    /// `ident` in the first scope that defines it (or None if no scopes define it).
+    ///
+    /// A block's items are above its local variables in the scope hierarchy, regardless of where
+    /// the items are defined in the block. For example,
+    /// ```rust
+    /// fn f() {
+    ///    g(); // Since there are no local variables in scope yet, this resolves to the item.
+    ///    let g = || {};
+    ///    fn g() {}
+    ///    g(); // This resolves to the local variable `g` since it shadows the item.
+    /// }
+    /// ```
+    ///
+    /// Invariant: This must only be called during main resolution, not during
+    /// import resolution.
+    #[tracing::instrument(level = "debug", skip(self, ribs))]
+    crate fn resolve_ident_in_lexical_scope(
+        &mut self,
+        mut ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+        finalize_full: Finalize,
+        ribs: &[Rib<'a>],
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Option<LexicalScopeBinding<'a>> {
+        assert!(ns == TypeNS || ns == ValueNS);
+        let orig_ident = ident;
+        if ident.name == kw::Empty {
+            return Some(LexicalScopeBinding::Res(Res::Err));
+        }
+        let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
+            // FIXME(jseyfried) improve `Self` hygiene
+            let empty_span = ident.span.with_ctxt(SyntaxContext::root());
+            (empty_span, empty_span)
+        } else if ns == TypeNS {
+            let normalized_span = ident.span.normalize_to_macros_2_0();
+            (normalized_span, normalized_span)
+        } else {
+            (ident.span.normalize_to_macro_rules(), ident.span.normalize_to_macros_2_0())
+        };
+        ident.span = general_span;
+        let normalized_ident = Ident { span: normalized_span, ..ident };
+
+        // Walk backwards up the ribs in scope.
+        let finalize = finalize_full.path_span();
+        let mut module = self.graph_root;
+        for i in (0..ribs.len()).rev() {
+            debug!("walk rib\n{:?}", ribs[i].bindings);
+            // Use the rib kind to determine whether we are resolving parameters
+            // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
+            let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
+            if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
+            {
+                // The ident resolves to a type parameter or local variable.
+                return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
+                    i,
+                    rib_ident,
+                    *res,
+                    finalize,
+                    *original_rib_ident_def,
+                    ribs,
+                )));
+            }
+
+            module = match ribs[i].kind {
+                ModuleRibKind(module) => module,
+                MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
+                    // If an invocation of this macro created `ident`, give up on `ident`
+                    // and switch to `ident`'s source from the macro definition.
+                    ident.span.remove_mark();
+                    continue;
+                }
+                _ => continue,
+            };
+
+            match module.kind {
+                ModuleKind::Block(..) => {} // We can see through blocks
+                _ => break,
+            }
+
+            let item = self.resolve_ident_in_module_unadjusted(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                parent_scope,
+                finalize,
+                false,
+                unusable_binding,
+            );
+            if let Ok(binding) = item {
+                // The ident resolves to an item.
+                return Some(LexicalScopeBinding::Item(binding));
+            }
+        }
+        self.early_resolve_ident_in_lexical_scope(
+            orig_ident,
+            ScopeSet::Late(ns, module, finalize_full.node_id()),
+            parent_scope,
+            finalize,
+            finalize.is_some(),
+            false,
+            unusable_binding,
+        )
+        .ok()
+        .map(LexicalScopeBinding::Item)
+    }
+
+    /// Resolve an identifier in lexical scope.
+    /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
+    /// expansion and import resolution (perhaps they can be merged in the future).
+    /// The function is used for resolving initial segments of macro paths (e.g., `foo` in
+    /// `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
+    #[tracing::instrument(level = "debug", skip(self, scope_set))]
+    crate fn early_resolve_ident_in_lexical_scope(
+        &mut self,
+        orig_ident: Ident,
+        scope_set: ScopeSet<'a>,
+        parent_scope: &ParentScope<'a>,
+        finalize: Option<Span>,
+        force: bool,
+        last_import_segment: bool,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Result<&'a NameBinding<'a>, Determinacy> {
+        bitflags::bitflags! {
+            struct Flags: u8 {
+                const MACRO_RULES          = 1 << 0;
+                const MODULE               = 1 << 1;
+                const MISC_SUGGEST_CRATE   = 1 << 2;
+                const MISC_SUGGEST_SELF    = 1 << 3;
+                const MISC_FROM_PRELUDE    = 1 << 4;
+            }
+        }
+
+        assert!(force || !finalize.is_some()); // `finalize` implies `force`
+
+        // Make sure `self`, `super` etc produce an error when passed to here.
+        if orig_ident.is_path_segment_keyword() {
+            return Err(Determinacy::Determined);
+        }
+
+        let (ns, macro_kind, is_import) = match scope_set {
+            ScopeSet::All(ns, is_import) => (ns, None, is_import),
+            ScopeSet::AbsolutePath(ns) => (ns, None, false),
+            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
+            ScopeSet::Late(ns, ..) => (ns, None, false),
+        };
+
+        // This is *the* result, resolution from the scope closest to the resolved identifier.
+        // However, sometimes this result is "weak" because it comes from a glob import or
+        // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
+        // mod m { ... } // solution in outer scope
+        // {
+        //     use prefix::*; // imports another `m` - innermost solution
+        //                    // weak, cannot shadow the outer `m`, need to report ambiguity error
+        //     m::mac!();
+        // }
+        // So we have to save the innermost solution and continue searching in outer scopes
+        // to detect potential ambiguities.
+        let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
+        let mut determinacy = Determinacy::Determined;
+
+        // Go through all the scopes and try to resolve the name.
+        let break_result = self.visit_scopes(
+            scope_set,
+            parent_scope,
+            orig_ident.span.ctxt(),
+            |this, scope, use_prelude, ctxt| {
+                let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
+                let ok = |res, span, arenas| {
+                    Ok((
+                        (res, ty::Visibility::Public, span, LocalExpnId::ROOT)
+                            .to_name_binding(arenas),
+                        Flags::empty(),
+                    ))
+                };
+                let result = match scope {
+                    Scope::DeriveHelpers(expn_id) => {
+                        if let Some(attr) = this
+                            .helper_attrs
+                            .get(&expn_id)
+                            .and_then(|attrs| attrs.iter().rfind(|i| ident == **i))
+                        {
+                            let binding = (
+                                Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
+                                ty::Visibility::Public,
+                                attr.span,
+                                expn_id,
+                            )
+                                .to_name_binding(this.arenas);
+                            Ok((binding, Flags::empty()))
+                        } else {
+                            Err(Determinacy::Determined)
+                        }
+                    }
+                    Scope::DeriveHelpersCompat => {
+                        let mut result = Err(Determinacy::Determined);
+                        for derive in parent_scope.derives {
+                            let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
+                            match this.resolve_macro_path(
+                                derive,
+                                Some(MacroKind::Derive),
+                                parent_scope,
+                                true,
+                                force,
+                            ) {
+                                Ok((Some(ext), _)) => {
+                                    if ext.helper_attrs.contains(&ident.name) {
+                                        result = ok(
+                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
+                                            derive.span,
+                                            this.arenas,
+                                        );
+                                        break;
+                                    }
+                                }
+                                Ok(_) | Err(Determinacy::Determined) => {}
+                                Err(Determinacy::Undetermined) => {
+                                    result = Err(Determinacy::Undetermined)
+                                }
+                            }
+                        }
+                        result
+                    }
+                    Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
+                        MacroRulesScope::Binding(macro_rules_binding)
+                            if ident == macro_rules_binding.ident =>
+                        {
+                            Ok((macro_rules_binding.binding, Flags::MACRO_RULES))
+                        }
+                        MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
+                        _ => Err(Determinacy::Determined),
+                    },
+                    Scope::CrateRoot => {
+                        let root_ident = Ident::new(kw::PathRoot, ident.span);
+                        let root_module = this.resolve_crate_root(root_ident);
+                        let binding = this.resolve_ident_in_module_ext(
+                            ModuleOrUniformRoot::Module(root_module),
+                            ident,
+                            ns,
+                            parent_scope,
+                            finalize,
+                            last_import_segment,
+                            unusable_binding,
+                        );
+                        match binding {
+                            Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
+                            Err((Determinacy::Undetermined, Weak::No)) => {
+                                return Some(Err(Determinacy::determined(force)));
+                            }
+                            Err((Determinacy::Undetermined, Weak::Yes)) => {
+                                Err(Determinacy::Undetermined)
+                            }
+                            Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
+                        }
+                    }
+                    Scope::Module(module, derive_fallback_lint_id) => {
+                        let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
+                        let binding = this.resolve_ident_in_module_unadjusted_ext(
+                            ModuleOrUniformRoot::Module(module),
+                            ident,
+                            ns,
+                            adjusted_parent_scope,
+                            !matches!(scope_set, ScopeSet::Late(..)),
+                            finalize,
+                            last_import_segment,
+                            unusable_binding,
+                        );
+                        match binding {
+                            Ok(binding) => {
+                                if let Some(lint_id) = derive_fallback_lint_id {
+                                    this.lint_buffer.buffer_lint_with_diagnostic(
+                                        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+                                        lint_id,
+                                        orig_ident.span,
+                                        &format!(
+                                            "cannot find {} `{}` in this scope",
+                                            ns.descr(),
+                                            ident
+                                        ),
+                                        BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
+                                            orig_ident.span,
+                                        ),
+                                    );
+                                }
+                                let misc_flags = if ptr::eq(module, this.graph_root) {
+                                    Flags::MISC_SUGGEST_CRATE
+                                } else if module.is_normal() {
+                                    Flags::MISC_SUGGEST_SELF
+                                } else {
+                                    Flags::empty()
+                                };
+                                Ok((binding, Flags::MODULE | misc_flags))
+                            }
+                            Err((Determinacy::Undetermined, Weak::No)) => {
+                                return Some(Err(Determinacy::determined(force)));
+                            }
+                            Err((Determinacy::Undetermined, Weak::Yes)) => {
+                                Err(Determinacy::Undetermined)
+                            }
+                            Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
+                        }
+                    }
+                    Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() {
+                        Some(ident) => ok(
+                            Res::NonMacroAttr(NonMacroAttrKind::Registered),
+                            ident.span,
+                            this.arenas,
+                        ),
+                        None => Err(Determinacy::Determined),
+                    },
+                    Scope::MacroUsePrelude => {
+                        match this.macro_use_prelude.get(&ident.name).cloned() {
+                            Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)),
+                            None => Err(Determinacy::determined(
+                                this.graph_root.unexpanded_invocations.borrow().is_empty(),
+                            )),
+                        }
+                    }
+                    Scope::BuiltinAttrs => {
+                        if is_builtin_attr_name(ident.name) {
+                            ok(
+                                Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)),
+                                DUMMY_SP,
+                                this.arenas,
+                            )
+                        } else {
+                            Err(Determinacy::Determined)
+                        }
+                    }
+                    Scope::ExternPrelude => {
+                        match this.extern_prelude_get(ident, finalize.is_some()) {
+                            Some(binding) => Ok((binding, Flags::empty())),
+                            None => Err(Determinacy::determined(
+                                this.graph_root.unexpanded_invocations.borrow().is_empty(),
+                            )),
+                        }
+                    }
+                    Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() {
+                        Some(ident) => ok(Res::ToolMod, ident.span, this.arenas),
+                        None => Err(Determinacy::Determined),
+                    },
+                    Scope::StdLibPrelude => {
+                        let mut result = Err(Determinacy::Determined);
+                        if let Some(prelude) = this.prelude {
+                            if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
+                                ModuleOrUniformRoot::Module(prelude),
+                                ident,
+                                ns,
+                                parent_scope,
+                                None,
+                                last_import_segment,
+                                unusable_binding,
+                            ) {
+                                if use_prelude || this.is_builtin_macro(binding.res()) {
+                                    result = Ok((binding, Flags::MISC_FROM_PRELUDE));
+                                }
+                            }
+                        }
+                        result
+                    }
+                    Scope::BuiltinTypes => match PrimTy::from_name(ident.name) {
+                        Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
+                        None => Err(Determinacy::Determined),
+                    },
+                };
+
+                match result {
+                    Ok((binding, flags))
+                        if sub_namespace_match(binding.macro_kind(), macro_kind) =>
+                    {
+                        if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) {
+                            return Some(Ok(binding));
+                        }
+
+                        if let Some((innermost_binding, innermost_flags)) = innermost_result {
+                            // 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 is_builtin = |res| {
+                                    matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
+                                };
+                                let derive_helper =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
+                                let derive_helper_compat =
+                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
+
+                                let ambiguity_error_kind = if is_import {
+                                    Some(AmbiguityKind::Import)
+                                } else if is_builtin(innermost_res) || is_builtin(res) {
+                                    Some(AmbiguityKind::BuiltinAttr)
+                                } else if innermost_res == derive_helper_compat
+                                    || res == derive_helper_compat && innermost_res != derive_helper
+                                {
+                                    Some(AmbiguityKind::DeriveHelper)
+                                } else if innermost_flags.contains(Flags::MACRO_RULES)
+                                    && flags.contains(Flags::MODULE)
+                                    && !this.disambiguate_macro_rules_vs_modularized(
+                                        innermost_binding,
+                                        binding,
+                                    )
+                                    || flags.contains(Flags::MACRO_RULES)
+                                        && innermost_flags.contains(Flags::MODULE)
+                                        && !this.disambiguate_macro_rules_vs_modularized(
+                                            binding,
+                                            innermost_binding,
+                                        )
+                                {
+                                    Some(AmbiguityKind::MacroRulesVsModularized)
+                                } else if innermost_binding.is_glob_import() {
+                                    Some(AmbiguityKind::GlobVsOuter)
+                                } else if innermost_binding
+                                    .may_appear_after(parent_scope.expansion, binding)
+                                {
+                                    Some(AmbiguityKind::MoreExpandedVsOuter)
+                                } else {
+                                    None
+                                };
+                                if let Some(kind) = ambiguity_error_kind {
+                                    let misc = |f: Flags| {
+                                        if f.contains(Flags::MISC_SUGGEST_CRATE) {
+                                            AmbiguityErrorMisc::SuggestCrate
+                                        } else if f.contains(Flags::MISC_SUGGEST_SELF) {
+                                            AmbiguityErrorMisc::SuggestSelf
+                                        } else if f.contains(Flags::MISC_FROM_PRELUDE) {
+                                            AmbiguityErrorMisc::FromPrelude
+                                        } else {
+                                            AmbiguityErrorMisc::None
+                                        }
+                                    };
+                                    this.ambiguity_errors.push(AmbiguityError {
+                                        kind,
+                                        ident: orig_ident,
+                                        b1: innermost_binding,
+                                        b2: binding,
+                                        misc1: misc(innermost_flags),
+                                        misc2: misc(flags),
+                                    });
+                                    return Some(Ok(innermost_binding));
+                                }
+                            }
+                        } else {
+                            // Found the first solution.
+                            innermost_result = Some((binding, flags));
+                        }
+                    }
+                    Ok(..) | Err(Determinacy::Determined) => {}
+                    Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined,
+                }
+
+                None
+            },
+        );
+
+        if let Some(break_result) = break_result {
+            return break_result;
+        }
+
+        // The first found solution was the only one, return it.
+        if let Some((binding, _)) = innermost_result {
+            return Ok(binding);
+        }
+
+        Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    crate fn maybe_resolve_ident_in_module(
+        &mut self,
+        module: ModuleOrUniformRoot<'a>,
+        ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+    ) -> Result<&'a NameBinding<'a>, Determinacy> {
+        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, None, false, None)
+            .map_err(|(determinacy, _)| determinacy)
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    crate fn resolve_ident_in_module(
+        &mut self,
+        module: ModuleOrUniformRoot<'a>,
+        ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+        finalize: Option<Span>,
+        // We are resolving a last import segment during import validation.
+        last_import_segment: bool,
+        // This binding should be ignored during in-module resolution, so that we don't get
+        // "self-confirming" import resolutions during import validation.
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Result<&'a NameBinding<'a>, Determinacy> {
+        self.resolve_ident_in_module_ext(
+            module,
+            ident,
+            ns,
+            parent_scope,
+            finalize,
+            last_import_segment,
+            unusable_binding,
+        )
+        .map_err(|(determinacy, _)| determinacy)
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_ident_in_module_ext(
+        &mut self,
+        module: ModuleOrUniformRoot<'a>,
+        mut ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+        finalize: Option<Span>,
+        last_import_segment: bool,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
+        let tmp_parent_scope;
+        let mut adjusted_parent_scope = parent_scope;
+        match module {
+            ModuleOrUniformRoot::Module(m) => {
+                if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) {
+                    tmp_parent_scope =
+                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
+                    adjusted_parent_scope = &tmp_parent_scope;
+                }
+            }
+            ModuleOrUniformRoot::ExternPrelude => {
+                ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root());
+            }
+            ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => {
+                // No adjustments
+            }
+        }
+        self.resolve_ident_in_module_unadjusted_ext(
+            module,
+            ident,
+            ns,
+            adjusted_parent_scope,
+            false,
+            finalize,
+            last_import_segment,
+            unusable_binding,
+        )
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_ident_in_module_unadjusted(
+        &mut self,
+        module: ModuleOrUniformRoot<'a>,
+        ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+        finalize: Option<Span>,
+        last_import_segment: bool,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Result<&'a NameBinding<'a>, Determinacy> {
+        self.resolve_ident_in_module_unadjusted_ext(
+            module,
+            ident,
+            ns,
+            parent_scope,
+            false,
+            finalize,
+            last_import_segment,
+            unusable_binding,
+        )
+        .map_err(|(determinacy, _)| determinacy)
+    }
+
+    /// Attempts to resolve `ident` in namespaces `ns` of `module`.
+    /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete.
+    #[tracing::instrument(level = "debug", skip(self))]
+    fn resolve_ident_in_module_unadjusted_ext(
+        &mut self,
+        module: ModuleOrUniformRoot<'a>,
+        ident: Ident,
+        ns: Namespace,
+        parent_scope: &ParentScope<'a>,
+        restricted_shadowing: bool,
+        finalize: Option<Span>,
+        last_import_segment: bool,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
+        let module = match module {
+            ModuleOrUniformRoot::Module(module) => module,
+            ModuleOrUniformRoot::CrateRootAndExternPrelude => {
+                assert!(!restricted_shadowing);
+                let binding = self.early_resolve_ident_in_lexical_scope(
+                    ident,
+                    ScopeSet::AbsolutePath(ns),
+                    parent_scope,
+                    finalize,
+                    finalize.is_some(),
+                    last_import_segment,
+                    unusable_binding,
+                );
+                return binding.map_err(|determinacy| (determinacy, Weak::No));
+            }
+            ModuleOrUniformRoot::ExternPrelude => {
+                assert!(!restricted_shadowing);
+                return if ns != TypeNS {
+                    Err((Determined, Weak::No))
+                } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) {
+                    Ok(binding)
+                } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
+                    // Macro-expanded `extern crate` items can add names to extern prelude.
+                    Err((Undetermined, Weak::No))
+                } else {
+                    Err((Determined, Weak::No))
+                };
+            }
+            ModuleOrUniformRoot::CurrentScope => {
+                assert!(!restricted_shadowing);
+                if ns == TypeNS {
+                    if ident.name == kw::Crate || ident.name == kw::DollarCrate {
+                        let module = self.resolve_crate_root(ident);
+                        let binding =
+                            (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT)
+                                .to_name_binding(self.arenas);
+                        return Ok(binding);
+                    } else if ident.name == kw::Super || ident.name == kw::SelfLower {
+                        // FIXME: Implement these with renaming requirements so that e.g.
+                        // `use super;` doesn't work, but `use super as name;` does.
+                        // Fall through here to get an error from `early_resolve_...`.
+                    }
+                }
+
+                let scopes = ScopeSet::All(ns, true);
+                let binding = self.early_resolve_ident_in_lexical_scope(
+                    ident,
+                    scopes,
+                    parent_scope,
+                    finalize,
+                    finalize.is_some(),
+                    last_import_segment,
+                    unusable_binding,
+                );
+                return binding.map_err(|determinacy| (determinacy, Weak::No));
+            }
+        };
+
+        let key = self.new_key(ident, ns);
+        let resolution =
+            self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
+
+        if let Some(path_span) = finalize {
+            // If the primary binding is unusable, search further and return the shadowed glob
+            // binding if it exists. What we really want here is having two separate scopes in
+            // a module - one for non-globs and one for globs, but until that's done use this
+            // hack to avoid inconsistent resolution ICEs during import validation.
+            let binding = [resolution.binding, resolution.shadowed_glob]
+                .into_iter()
+                .filter_map(|binding| match (binding, unusable_binding) {
+                    (Some(binding), Some(unusable_binding))
+                        if ptr::eq(binding, unusable_binding) =>
+                    {
+                        None
+                    }
+                    _ => binding,
+                })
+                .next();
+            let Some(binding) = binding else {
+                return Err((Determined, Weak::No));
+            };
+
+            if !self.is_accessible_from(binding.vis, parent_scope.module) {
+                if last_import_segment {
+                    return Err((Determined, Weak::No));
+                } else {
+                    self.privacy_errors.push(PrivacyError {
+                        ident,
+                        binding,
+                        dedup_span: path_span,
+                    });
+                }
+            }
+
+            // Forbid expanded shadowing to avoid time travel.
+            if let Some(shadowed_glob) = resolution.shadowed_glob
+                && restricted_shadowing
+                && binding.expansion != LocalExpnId::ROOT
+                && binding.res() != shadowed_glob.res()
+            {
+                self.ambiguity_errors.push(AmbiguityError {
+                    kind: AmbiguityKind::GlobVsExpanded,
+                    ident,
+                    b1: binding,
+                    b2: shadowed_glob,
+                    misc1: AmbiguityErrorMisc::None,
+                    misc2: AmbiguityErrorMisc::None,
+                });
+            }
+
+            if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT {
+                if let NameBindingKind::Res(_, true) = binding.kind {
+                    self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
+                }
+            }
+
+            self.record_use(ident, binding, restricted_shadowing);
+            return Ok(binding);
+        }
+
+        let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
+            if let Some(unusable_binding) = unusable_binding {
+                if ptr::eq(binding, unusable_binding) {
+                    return Err((Determined, Weak::No));
+                }
+            }
+            let usable = this.is_accessible_from(binding.vis, parent_scope.module);
+            if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
+        };
+
+        // Items and single imports are not shadowable, if we have one, then it's determined.
+        if let Some(binding) = resolution.binding {
+            if !binding.is_glob_import() {
+                return check_usable(self, binding);
+            }
+        }
+
+        // --- From now on we either have a glob resolution or no resolution. ---
+
+        // Check if one of single imports can still define the name,
+        // if it can then our result is not determined and can be invalidated.
+        for single_import in &resolution.single_imports {
+            if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
+                continue;
+            }
+            let Some(module) = single_import.imported_module.get() else {
+                return Err((Undetermined, Weak::No));
+            };
+            let ImportKind::Single { source: ident, .. } = single_import.kind else {
+                unreachable!();
+            };
+            match self.resolve_ident_in_module(
+                module,
+                ident,
+                ns,
+                &single_import.parent_scope,
+                None,
+                last_import_segment,
+                unusable_binding,
+            ) {
+                Err(Determined) => continue,
+                Ok(binding)
+                    if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) =>
+                {
+                    continue;
+                }
+                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)),
+            }
+        }
+
+        // So we have a resolution that's from a glob import. This resolution is determined
+        // if it cannot be shadowed by some new item/import expanded from a macro.
+        // This happens either if there are no unexpanded macros, or expanded names cannot
+        // shadow globs (that happens in macro namespace or with restricted shadowing).
+        //
+        // Additionally, any macro in any module can plant names in the root module if it creates
+        // `macro_export` macros, so the root module effectively has unresolved invocations if any
+        // module has unresolved invocations.
+        // However, it causes resolution/expansion to stuck too often (#53144), so, to make
+        // progress, we have to ignore those potential unresolved invocations from other modules
+        // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
+        // shadowing is enabled, see `macro_expanded_macro_export_errors`).
+        let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
+        if let Some(binding) = resolution.binding {
+            if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
+                return check_usable(self, binding);
+            } else {
+                return Err((Undetermined, Weak::No));
+            }
+        }
+
+        // --- From now on we have no resolution. ---
+
+        // Now we are in situation when new item/import can appear only from a glob or a macro
+        // expansion. With restricted shadowing names from globs and macro expansions cannot
+        // shadow names from outer scopes, so we can freely fallback from module search to search
+        // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer
+        // scopes we return `Undetermined` with `Weak::Yes`.
+
+        // Check if one of unexpanded macros can still define the name,
+        // if it can then our "no resolution" result is not determined and can be invalidated.
+        if unexpanded_macros {
+            return Err((Undetermined, Weak::Yes));
+        }
+
+        // Check if one of glob imports can still define the name,
+        // if it can then our "no resolution" result is not determined and can be invalidated.
+        for glob_import in module.globs.borrow().iter() {
+            if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) {
+                continue;
+            }
+            let module = match glob_import.imported_module.get() {
+                Some(ModuleOrUniformRoot::Module(module)) => module,
+                Some(_) => continue,
+                None => return Err((Undetermined, Weak::Yes)),
+            };
+            let tmp_parent_scope;
+            let (mut adjusted_parent_scope, mut ident) =
+                (parent_scope, ident.normalize_to_macros_2_0());
+            match ident.span.glob_adjust(module.expansion, glob_import.span) {
+                Some(Some(def)) => {
+                    tmp_parent_scope =
+                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
+                    adjusted_parent_scope = &tmp_parent_scope;
+                }
+                Some(None) => {}
+                None => continue,
+            };
+            let result = self.resolve_ident_in_module_unadjusted(
+                ModuleOrUniformRoot::Module(module),
+                ident,
+                ns,
+                adjusted_parent_scope,
+                None,
+                last_import_segment,
+                unusable_binding,
+            );
+
+            match result {
+                Err(Determined) => continue,
+                Ok(binding)
+                    if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) =>
+                {
+                    continue;
+                }
+                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)),
+            }
+        }
+
+        // No resolution and no one else can define the name - determinate error.
+        Err((Determined, Weak::No))
+    }
+
+    /// Validate a local resolution (from ribs).
+    #[tracing::instrument(level = "debug", skip(self, all_ribs))]
+    fn validate_res_from_ribs(
+        &mut self,
+        rib_index: usize,
+        rib_ident: Ident,
+        mut res: Res,
+        finalize: Option<Span>,
+        original_rib_ident_def: Ident,
+        all_ribs: &[Rib<'a>],
+    ) -> Res {
+        const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation";
+        debug!("validate_res_from_ribs({:?})", res);
+        let ribs = &all_ribs[rib_index + 1..];
+
+        // An invalid forward use of a generic parameter from a previous default.
+        if let ForwardGenericParamBanRibKind = all_ribs[rib_index].kind {
+            if let Some(span) = finalize {
+                let res_error = if rib_ident.name == kw::SelfUpper {
+                    ResolutionError::SelfInGenericParamDefault
+                } else {
+                    ResolutionError::ForwardDeclaredGenericParam
+                };
+                self.report_error(span, res_error);
+            }
+            assert_eq!(res, Res::Err);
+            return Res::Err;
+        }
+
+        match res {
+            Res::Local(_) => {
+                use ResolutionError::*;
+                let mut res_err = None;
+
+                for rib in ribs {
+                    match rib.kind {
+                        NormalRibKind
+                        | ClosureOrAsyncRibKind
+                        | ModuleRibKind(..)
+                        | MacroDefinition(..)
+                        | ForwardGenericParamBanRibKind => {
+                            // Nothing to do. Continue.
+                        }
+                        ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
+                            // This was an attempt to access an upvar inside a
+                            // named function item. This is not allowed, so we
+                            // report an error.
+                            if let Some(span) = finalize {
+                                // We don't immediately trigger a resolve error, because
+                                // we want certain other resolution errors (namely those
+                                // emitted for `ConstantItemRibKind` below) to take
+                                // precedence.
+                                res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem));
+                            }
+                        }
+                        ConstantItemRibKind(_, item) => {
+                            // Still doesn't deal with upvars
+                            if let Some(span) = finalize {
+                                let (span, resolution_error) =
+                                    if let Some((ident, constant_item_kind)) = item {
+                                        let kind_str = match constant_item_kind {
+                                            ConstantItemKind::Const => "const",
+                                            ConstantItemKind::Static => "static",
+                                        };
+                                        (
+                                            span,
+                                            AttemptToUseNonConstantValueInConstant(
+                                                ident, "let", kind_str,
+                                            ),
+                                        )
+                                    } else {
+                                        (
+                                            rib_ident.span,
+                                            AttemptToUseNonConstantValueInConstant(
+                                                original_rib_ident_def,
+                                                "const",
+                                                "let",
+                                            ),
+                                        )
+                                    };
+                                self.report_error(span, resolution_error);
+                            }
+                            return Res::Err;
+                        }
+                        ConstParamTyRibKind => {
+                            if let Some(span) = finalize {
+                                self.report_error(span, ParamInTyOfConstParam(rib_ident.name));
+                            }
+                            return Res::Err;
+                        }
+                    }
+                }
+                if let Some((span, res_err)) = res_err {
+                    self.report_error(span, res_err);
+                    return Res::Err;
+                }
+            }
+            Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
+                for rib in ribs {
+                    let has_generic_params: HasGenericParams = match rib.kind {
+                        NormalRibKind
+                        | ClosureOrAsyncRibKind
+                        | AssocItemRibKind
+                        | ModuleRibKind(..)
+                        | MacroDefinition(..)
+                        | ForwardGenericParamBanRibKind => {
+                            // Nothing to do. Continue.
+                            continue;
+                        }
+
+                        ConstantItemRibKind(trivial, _) => {
+                            let features = self.session.features_untracked();
+                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+                            if !(trivial || features.generic_const_exprs) {
+                                // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
+                                // we can't easily tell if it's generic at this stage, so we instead remember
+                                // this and then enforce the self type to be concrete later on.
+                                if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
+                                    res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
+                                } else {
+                                    if let Some(span) = finalize {
+                                        self.report_error(
+                                            span,
+                                            ResolutionError::ParamInNonTrivialAnonConst {
+                                                name: rib_ident.name,
+                                                is_type: true,
+                                            },
+                                        );
+                                        self.session.delay_span_bug(span, CG_BUG_STR);
+                                    }
+
+                                    return Res::Err;
+                                }
+                            }
+
+                            continue;
+                        }
+
+                        // This was an attempt to use a type parameter outside its scope.
+                        ItemRibKind(has_generic_params) => has_generic_params,
+                        FnItemRibKind => HasGenericParams::Yes,
+                        ConstParamTyRibKind => {
+                            if let Some(span) = finalize {
+                                self.report_error(
+                                    span,
+                                    ResolutionError::ParamInTyOfConstParam(rib_ident.name),
+                                );
+                            }
+                            return Res::Err;
+                        }
+                    };
+
+                    if let Some(span) = finalize {
+                        self.report_error(
+                            span,
+                            ResolutionError::GenericParamsFromOuterFunction(
+                                res,
+                                has_generic_params,
+                            ),
+                        );
+                    }
+                    return Res::Err;
+                }
+            }
+            Res::Def(DefKind::ConstParam, _) => {
+                let mut ribs = ribs.iter().peekable();
+                if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() {
+                    // When declaring const parameters inside function signatures, the first rib
+                    // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it
+                    // (spuriously) conflicting with the const param.
+                    ribs.next();
+                }
+
+                for rib in ribs {
+                    let has_generic_params = match rib.kind {
+                        NormalRibKind
+                        | ClosureOrAsyncRibKind
+                        | AssocItemRibKind
+                        | ModuleRibKind(..)
+                        | MacroDefinition(..)
+                        | ForwardGenericParamBanRibKind => continue,
+
+                        ConstantItemRibKind(trivial, _) => {
+                            let features = self.session.features_untracked();
+                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+                            if !(trivial || features.generic_const_exprs) {
+                                if let Some(span) = finalize {
+                                    self.report_error(
+                                        span,
+                                        ResolutionError::ParamInNonTrivialAnonConst {
+                                            name: rib_ident.name,
+                                            is_type: false,
+                                        },
+                                    );
+                                    self.session.delay_span_bug(span, CG_BUG_STR);
+                                }
+
+                                return Res::Err;
+                            }
+
+                            continue;
+                        }
+
+                        ItemRibKind(has_generic_params) => has_generic_params,
+                        FnItemRibKind => HasGenericParams::Yes,
+                        ConstParamTyRibKind => {
+                            if let Some(span) = finalize {
+                                self.report_error(
+                                    span,
+                                    ResolutionError::ParamInTyOfConstParam(rib_ident.name),
+                                );
+                            }
+                            return Res::Err;
+                        }
+                    };
+
+                    // This was an attempt to use a const parameter outside its scope.
+                    if let Some(span) = finalize {
+                        self.report_error(
+                            span,
+                            ResolutionError::GenericParamsFromOuterFunction(
+                                res,
+                                has_generic_params,
+                            ),
+                        );
+                    }
+                    return Res::Err;
+                }
+            }
+            _ => {}
+        }
+        res
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    crate fn maybe_resolve_path(
+        &mut self,
+        path: &[Segment],
+        opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        parent_scope: &ParentScope<'a>,
+    ) -> PathResult<'a> {
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, Finalize::No, None, None)
+    }
+
+    #[tracing::instrument(level = "debug", skip(self))]
+    crate fn resolve_path(
+        &mut self,
+        path: &[Segment],
+        opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        parent_scope: &ParentScope<'a>,
+        finalize: Finalize,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> PathResult<'a> {
+        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None, unusable_binding)
+    }
+
+    crate fn resolve_path_with_ribs(
+        &mut self,
+        path: &[Segment],
+        opt_ns: Option<Namespace>, // `None` indicates a module path in import
+        parent_scope: &ParentScope<'a>,
+        finalize_full: Finalize,
+        ribs: Option<&PerNS<Vec<Rib<'a>>>>,
+        unusable_binding: Option<&'a NameBinding<'a>>,
+    ) -> PathResult<'a> {
+        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full);
+
+        let finalize = finalize_full.path_span();
+        let mut module = None;
+        let mut allow_super = true;
+        let mut second_binding = None;
+
+        for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
+            debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
+            let record_segment_res = |this: &mut Self, res| {
+                if finalize.is_some() {
+                    if let Some(id) = id {
+                        if !this.partial_res_map.contains_key(&id) {
+                            assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
+                            this.record_partial_res(id, PartialRes::new(res));
+                        }
+                    }
+                }
+            };
+
+            let is_last = i == path.len() - 1;
+            let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
+            let name = ident.name;
+
+            allow_super &= ns == TypeNS && (name == kw::SelfLower || name == kw::Super);
+
+            if ns == TypeNS {
+                if allow_super && name == kw::Super {
+                    let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
+                    let self_module = match i {
+                        0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
+                        _ => match module {
+                            Some(ModuleOrUniformRoot::Module(module)) => Some(module),
+                            _ => None,
+                        },
+                    };
+                    if let Some(self_module) = self_module {
+                        if let Some(parent) = self_module.parent {
+                            module = Some(ModuleOrUniformRoot::Module(
+                                self.resolve_self(&mut ctxt, parent),
+                            ));
+                            continue;
+                        }
+                    }
+                    return PathResult::failed(ident.span, false, finalize.is_some(), || {
+                        ("there are too many leading `super` keywords".to_string(), None)
+                    });
+                }
+                if i == 0 {
+                    if name == kw::SelfLower {
+                        let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
+                        module = Some(ModuleOrUniformRoot::Module(
+                            self.resolve_self(&mut ctxt, parent_scope.module),
+                        ));
+                        continue;
+                    }
+                    if name == kw::PathRoot && ident.span.rust_2018() {
+                        module = Some(ModuleOrUniformRoot::ExternPrelude);
+                        continue;
+                    }
+                    if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() {
+                        // `::a::b` from 2015 macro on 2018 global edition
+                        module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
+                        continue;
+                    }
+                    if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
+                        // `::a::b`, `crate::a::b` or `$crate::a::b`
+                        module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident)));
+                        continue;
+                    }
+                }
+            }
+
+            // Report special messages for path segment keywords in wrong positions.
+            if ident.is_path_segment_keyword() && i != 0 {
+                return PathResult::failed(ident.span, false, finalize.is_some(), || {
+                    let name_str = if name == kw::PathRoot {
+                        "crate root".to_string()
+                    } else {
+                        format!("`{}`", name)
+                    };
+                    let label = if i == 1 && path[0].ident.name == kw::PathRoot {
+                        format!("global paths cannot start with {}", name_str)
+                    } else {
+                        format!("{} in paths can only be used in start position", name_str)
+                    };
+                    (label, None)
+                });
+            }
+
+            enum FindBindingResult<'a> {
+                Binding(Result<&'a NameBinding<'a>, Determinacy>),
+                Res(Res),
+            }
+            let find_binding_in_ns = |this: &mut Self, ns| {
+                let binding = if let Some(module) = module {
+                    this.resolve_ident_in_module(
+                        module,
+                        ident,
+                        ns,
+                        parent_scope,
+                        finalize,
+                        false,
+                        unusable_binding,
+                    )
+                } else if let Some(ribs) = ribs
+                    && let Some(TypeNS | ValueNS) = opt_ns
+                {
+                    match this.resolve_ident_in_lexical_scope(
+                        ident,
+                        ns,
+                        parent_scope,
+                        finalize_full,
+                        &ribs[ns],
+                        unusable_binding,
+                    ) {
+                        // we found a locally-imported or available item/module
+                        Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
+                        // we found a local variable or type param
+                        Some(LexicalScopeBinding::Res(res)) => return FindBindingResult::Res(res),
+                        _ => Err(Determinacy::determined(finalize.is_some())),
+                    }
+                } else {
+                    let scopes = ScopeSet::All(ns, opt_ns.is_none());
+                    this.early_resolve_ident_in_lexical_scope(
+                        ident,
+                        scopes,
+                        parent_scope,
+                        finalize,
+                        finalize.is_some(),
+                        false,
+                        unusable_binding,
+                    )
+                };
+                FindBindingResult::Binding(binding)
+            };
+            let binding = match find_binding_in_ns(self, ns) {
+                FindBindingResult::Res(res) => {
+                    record_segment_res(self, res);
+                    return PathResult::NonModule(PartialRes::with_unresolved_segments(
+                        res,
+                        path.len() - 1,
+                    ));
+                }
+                FindBindingResult::Binding(binding) => binding,
+            };
+            match binding {
+                Ok(binding) => {
+                    if i == 1 {
+                        second_binding = Some(binding);
+                    }
+                    let res = binding.res();
+                    let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
+                    if let Some(next_module) = binding.module() {
+                        module = Some(ModuleOrUniformRoot::Module(next_module));
+                        record_segment_res(self, res);
+                    } else if res == Res::ToolMod && i + 1 != path.len() {
+                        if binding.is_import() {
+                            self.session
+                                .struct_span_err(
+                                    ident.span,
+                                    "cannot use a tool module through an import",
+                                )
+                                .span_note(binding.span, "the tool module imported here")
+                                .emit();
+                        }
+                        let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
+                        return PathResult::NonModule(PartialRes::new(res));
+                    } else if res == Res::Err {
+                        return PathResult::NonModule(PartialRes::new(Res::Err));
+                    } else if opt_ns.is_some() && (is_last || maybe_assoc) {
+                        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+                        return PathResult::NonModule(PartialRes::with_unresolved_segments(
+                            res,
+                            path.len() - i - 1,
+                        ));
+                    } else {
+                        return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
+                            let label = format!(
+                                "`{ident}` is {} {}, not a module",
+                                res.article(),
+                                res.descr()
+                            );
+                            (label, None)
+                        });
+                    }
+                }
+                Err(Undetermined) => return PathResult::Indeterminate,
+                Err(Determined) => {
+                    if let Some(ModuleOrUniformRoot::Module(module)) = module {
+                        if opt_ns.is_some() && !module.is_normal() {
+                            return PathResult::NonModule(PartialRes::with_unresolved_segments(
+                                module.res().unwrap(),
+                                path.len() - i,
+                            ));
+                        }
+                    }
+
+                    return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
+                        self.report_path_resolution_error(
+                            path,
+                            opt_ns,
+                            parent_scope,
+                            ribs,
+                            unusable_binding,
+                            module,
+                            i,
+                            ident,
+                        )
+                    });
+                }
+            }
+        }
+
+        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
+
+        PathResult::Module(match module {
+            Some(module) => module,
+            None if path.is_empty() => ModuleOrUniformRoot::CurrentScope,
+            _ => bug!("resolve_path: non-empty path `{:?}` has no module", path),
+        })
+    }
+}
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 02abdba..aab0c1f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -2,12 +2,11 @@
 
 use crate::diagnostics::Suggestion;
 use crate::Determinacy::{self, *};
-use crate::Namespace::{self, MacroNS, TypeNS};
+use crate::Namespace::{MacroNS, TypeNS};
 use crate::{module_to_string, names_to_string};
-use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind};
-use crate::{BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
-use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet, Weak};
-use crate::{NameBinding, NameBindingKind, PathResult, PrivacyError, ToNameBinding};
+use crate::{AmbiguityKind, BindingKey, ModuleKind, ResolutionError, Resolver, Segment};
+use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
+use crate::{NameBinding, NameBindingKind, PathResult};
 
 use rustc_ast::NodeId;
 use rustc_data_structures::fx::FxHashSet;
@@ -125,15 +124,15 @@ pub fn is_nested(&self) -> bool {
     }
 }
 
-#[derive(Clone, Default, Debug)]
 /// Records information about the resolution of a name in a namespace of a module.
-pub struct NameResolution<'a> {
+#[derive(Clone, Default, Debug)]
+crate struct NameResolution<'a> {
     /// Single imports that may define the name in the namespace.
     /// Imports are arena-allocated, so it's ok to use pointers as keys.
-    single_imports: FxHashSet<Interned<'a, Import<'a>>>,
+    pub single_imports: FxHashSet<Interned<'a, Import<'a>>>,
     /// The least shadowable known binding for this name, or None if there are no known bindings.
     pub binding: Option<&'a NameBinding<'a>>,
-    shadowed_glob: Option<&'a NameBinding<'a>>,
+    pub shadowed_glob: Option<&'a NameBinding<'a>>,
 }
 
 impl<'a> NameResolution<'a> {
@@ -169,278 +168,6 @@ fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBindi
 }
 
 impl<'a> Resolver<'a> {
-    crate fn resolve_ident_in_module_unadjusted(
-        &mut self,
-        module: ModuleOrUniformRoot<'a>,
-        ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-    ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_unadjusted_ext(
-            module,
-            ident,
-            ns,
-            parent_scope,
-            false,
-            finalize,
-        )
-        .map_err(|(determinacy, _)| determinacy)
-    }
-
-    /// Attempts to resolve `ident` in namespaces `ns` of `module`.
-    /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete.
-    crate fn resolve_ident_in_module_unadjusted_ext(
-        &mut self,
-        module: ModuleOrUniformRoot<'a>,
-        ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'a>,
-        restricted_shadowing: bool,
-        finalize: Option<Span>,
-    ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
-        let module = match module {
-            ModuleOrUniformRoot::Module(module) => module,
-            ModuleOrUniformRoot::CrateRootAndExternPrelude => {
-                assert!(!restricted_shadowing);
-                let binding = self.early_resolve_ident_in_lexical_scope(
-                    ident,
-                    ScopeSet::AbsolutePath(ns),
-                    parent_scope,
-                    finalize,
-                    finalize.is_some(),
-                );
-                return binding.map_err(|determinacy| (determinacy, Weak::No));
-            }
-            ModuleOrUniformRoot::ExternPrelude => {
-                assert!(!restricted_shadowing);
-                return if ns != TypeNS {
-                    Err((Determined, Weak::No))
-                } else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) {
-                    Ok(binding)
-                } else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
-                    // Macro-expanded `extern crate` items can add names to extern prelude.
-                    Err((Undetermined, Weak::No))
-                } else {
-                    Err((Determined, Weak::No))
-                };
-            }
-            ModuleOrUniformRoot::CurrentScope => {
-                assert!(!restricted_shadowing);
-                if ns == TypeNS {
-                    if ident.name == kw::Crate || ident.name == kw::DollarCrate {
-                        let module = self.resolve_crate_root(ident);
-                        let binding =
-                            (module, ty::Visibility::Public, module.span, LocalExpnId::ROOT)
-                                .to_name_binding(self.arenas);
-                        return Ok(binding);
-                    } else if ident.name == kw::Super || ident.name == kw::SelfLower {
-                        // FIXME: Implement these with renaming requirements so that e.g.
-                        // `use super;` doesn't work, but `use super as name;` does.
-                        // Fall through here to get an error from `early_resolve_...`.
-                    }
-                }
-
-                let scopes = ScopeSet::All(ns, true);
-                let binding = self.early_resolve_ident_in_lexical_scope(
-                    ident,
-                    scopes,
-                    parent_scope,
-                    finalize,
-                    finalize.is_some(),
-                );
-                return binding.map_err(|determinacy| (determinacy, Weak::No));
-            }
-        };
-
-        let key = self.new_key(ident, ns);
-        let resolution =
-            self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
-
-        if let Some(binding) = resolution.binding && let Some(path_span) = finalize {
-            if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT {
-                if let NameBindingKind::Res(_, true) = binding.kind {
-                    self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
-                }
-            }
-        }
-
-        let check_usable = |this: &mut Self, binding: &'a NameBinding<'a>| {
-            if let Some(unusable_binding) = this.unusable_binding {
-                if ptr::eq(binding, unusable_binding) {
-                    return Err((Determined, Weak::No));
-                }
-            }
-            let usable = this.is_accessible_from(binding.vis, parent_scope.module);
-            if usable { Ok(binding) } else { Err((Determined, Weak::No)) }
-        };
-
-        if let Some(path_span) = finalize {
-            return resolution
-                .binding
-                .and_then(|binding| {
-                    // If the primary binding is unusable, search further and return the shadowed glob
-                    // binding if it exists. What we really want here is having two separate scopes in
-                    // a module - one for non-globs and one for globs, but until that's done use this
-                    // hack to avoid inconsistent resolution ICEs during import validation.
-                    if let Some(unusable_binding) = self.unusable_binding {
-                        if ptr::eq(binding, unusable_binding) {
-                            return resolution.shadowed_glob;
-                        }
-                    }
-                    Some(binding)
-                })
-                .ok_or((Determined, Weak::No))
-                .and_then(|binding| {
-                    if self.last_import_segment && check_usable(self, binding).is_err() {
-                        Err((Determined, Weak::No))
-                    } else {
-                        self.record_use(ident, binding, restricted_shadowing);
-
-                        if let Some(shadowed_glob) = resolution.shadowed_glob {
-                            // Forbid expanded shadowing to avoid time travel.
-                            if restricted_shadowing
-                                && binding.expansion != LocalExpnId::ROOT
-                                && binding.res() != shadowed_glob.res()
-                            {
-                                self.ambiguity_errors.push(AmbiguityError {
-                                    kind: AmbiguityKind::GlobVsExpanded,
-                                    ident,
-                                    b1: binding,
-                                    b2: shadowed_glob,
-                                    misc1: AmbiguityErrorMisc::None,
-                                    misc2: AmbiguityErrorMisc::None,
-                                });
-                            }
-                        }
-
-                        if !self.is_accessible_from(binding.vis, parent_scope.module) {
-                            self.privacy_errors.push(PrivacyError {
-                                ident,
-                                binding,
-                                dedup_span: path_span,
-                            });
-                        }
-
-                        Ok(binding)
-                    }
-                });
-        }
-
-        // Items and single imports are not shadowable, if we have one, then it's determined.
-        if let Some(binding) = resolution.binding {
-            if !binding.is_glob_import() {
-                return check_usable(self, binding);
-            }
-        }
-
-        // --- From now on we either have a glob resolution or no resolution. ---
-
-        // Check if one of single imports can still define the name,
-        // if it can then our result is not determined and can be invalidated.
-        for single_import in &resolution.single_imports {
-            if !self.is_accessible_from(single_import.vis.get(), parent_scope.module) {
-                continue;
-            }
-            let Some(module) = single_import.imported_module.get() else {
-                return Err((Undetermined, Weak::No));
-            };
-            let ImportKind::Single { source: ident, .. } = single_import.kind else {
-                unreachable!();
-            };
-            match self.resolve_ident_in_module(module, ident, ns, &single_import.parent_scope, None)
-            {
-                Err(Determined) => continue,
-                Ok(binding)
-                    if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) =>
-                {
-                    continue;
-                }
-                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::No)),
-            }
-        }
-
-        // So we have a resolution that's from a glob import. This resolution is determined
-        // if it cannot be shadowed by some new item/import expanded from a macro.
-        // This happens either if there are no unexpanded macros, or expanded names cannot
-        // shadow globs (that happens in macro namespace or with restricted shadowing).
-        //
-        // Additionally, any macro in any module can plant names in the root module if it creates
-        // `macro_export` macros, so the root module effectively has unresolved invocations if any
-        // module has unresolved invocations.
-        // However, it causes resolution/expansion to stuck too often (#53144), so, to make
-        // progress, we have to ignore those potential unresolved invocations from other modules
-        // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted
-        // shadowing is enabled, see `macro_expanded_macro_export_errors`).
-        let unexpanded_macros = !module.unexpanded_invocations.borrow().is_empty();
-        if let Some(binding) = resolution.binding {
-            if !unexpanded_macros || ns == MacroNS || restricted_shadowing {
-                return check_usable(self, binding);
-            } else {
-                return Err((Undetermined, Weak::No));
-            }
-        }
-
-        // --- From now on we have no resolution. ---
-
-        // Now we are in situation when new item/import can appear only from a glob or a macro
-        // expansion. With restricted shadowing names from globs and macro expansions cannot
-        // shadow names from outer scopes, so we can freely fallback from module search to search
-        // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer
-        // scopes we return `Undetermined` with `Weak::Yes`.
-
-        // Check if one of unexpanded macros can still define the name,
-        // if it can then our "no resolution" result is not determined and can be invalidated.
-        if unexpanded_macros {
-            return Err((Undetermined, Weak::Yes));
-        }
-
-        // Check if one of glob imports can still define the name,
-        // if it can then our "no resolution" result is not determined and can be invalidated.
-        for glob_import in module.globs.borrow().iter() {
-            if !self.is_accessible_from(glob_import.vis.get(), parent_scope.module) {
-                continue;
-            }
-            let module = match glob_import.imported_module.get() {
-                Some(ModuleOrUniformRoot::Module(module)) => module,
-                Some(_) => continue,
-                None => return Err((Undetermined, Weak::Yes)),
-            };
-            let tmp_parent_scope;
-            let (mut adjusted_parent_scope, mut ident) =
-                (parent_scope, ident.normalize_to_macros_2_0());
-            match ident.span.glob_adjust(module.expansion, glob_import.span) {
-                Some(Some(def)) => {
-                    tmp_parent_scope =
-                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
-                    adjusted_parent_scope = &tmp_parent_scope;
-                }
-                Some(None) => {}
-                None => continue,
-            };
-            let result = self.resolve_ident_in_module_unadjusted(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                adjusted_parent_scope,
-                None,
-            );
-
-            match result {
-                Err(Determined) => continue,
-                Ok(binding)
-                    if !self.is_accessible_from(binding.vis, glob_import.parent_scope.module) =>
-                {
-                    continue;
-                }
-                Ok(_) | Err(Undetermined) => return Err((Undetermined, Weak::Yes)),
-            }
-        }
-
-        // No resolution and no one else can define the name - determinate error.
-        Err((Determined, Weak::No))
-    }
-
     // Given a binding and an import that resolves to it,
     // return the corresponding binding defined by the import.
     crate fn import(
@@ -772,7 +499,7 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
             // not define any names while resolving its module path.
             let orig_vis = import.vis.replace(ty::Visibility::Invisible);
             let path_res =
-                self.r.resolve_path(&import.module_path, None, &import.parent_scope, Finalize::No);
+                self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
             import.vis.set(orig_vis);
 
             match path_res {
@@ -812,6 +539,8 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
                         ns,
                         &import.parent_scope,
                         None,
+                        false,
+                        None,
                     );
                     import.vis.set(orig_vis);
                     source_bindings[ns].set(binding);
@@ -857,10 +586,8 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let orig_unusable_binding = match &import.kind {
-            ImportKind::Single { target_bindings, .. } => {
-                Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get()))
-            }
+        let unusable_binding = match &import.kind {
+            ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
             _ => None,
         };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
@@ -869,12 +596,14 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
             root_span: import.root_span,
             path_span: import.span,
         };
-        let path_res =
-            self.r.resolve_path(&import.module_path, None, &import.parent_scope, finalize);
+        let path_res = self.r.resolve_path(
+            &import.module_path,
+            None,
+            &import.parent_scope,
+            finalize,
+            unusable_binding,
+        );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
-        if let Some(orig_unusable_binding) = orig_unusable_binding {
-            self.r.unusable_binding = orig_unusable_binding;
-        }
         import.vis.set(orig_vis);
         if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
             // Consider erroneous imports used to avoid duplicate diagnostics.
@@ -987,18 +716,15 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
         self.r.per_ns(|this, ns| {
             if !type_ns_only || ns == TypeNS {
                 let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-                let orig_unusable_binding =
-                    mem::replace(&mut this.unusable_binding, target_bindings[ns].get());
-                let orig_last_import_segment = mem::replace(&mut this.last_import_segment, true);
                 let binding = this.resolve_ident_in_module(
                     module,
                     ident,
                     ns,
                     &import.parent_scope,
                     Some(import.span),
+                    true,
+                    target_bindings[ns].get(),
                 );
-                this.last_import_segment = orig_last_import_segment;
-                this.unusable_binding = orig_unusable_binding;
                 import.vis.set(orig_vis);
 
                 match binding {
@@ -1057,6 +783,8 @@ fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImport
                         ns,
                         &import.parent_scope,
                         Some(import.span),
+                        false,
+                        None,
                     );
                     if binding.is_ok() {
                         all_ns_failed = false;
@@ -1271,15 +999,14 @@ fn check_for_redundant_imports(
                     return;
                 }
 
-                let orig_unusable_binding =
-                    mem::replace(&mut this.unusable_binding, target_bindings[ns].get());
-
                 match this.early_resolve_ident_in_lexical_scope(
                     target,
                     ScopeSet::All(ns, false),
                     &import.parent_scope,
                     None,
                     false,
+                    false,
+                    target_bindings[ns].get(),
                 ) {
                     Ok(other_binding) => {
                         is_redundant[ns] = Some(
@@ -1289,8 +1016,6 @@ fn check_for_redundant_imports(
                     }
                     Err(_) => is_redundant[ns] = Some(false),
                 }
-
-                this.unusable_binding = orig_unusable_binding;
             }
         });
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6fedabc..f27b60e 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -8,7 +8,7 @@
 use RibKind::*;
 
 use crate::{path_names_to_string, BindingError, Finalize, LexicalScopeBinding};
-use crate::{Module, ModuleOrUniformRoot, ParentScope, PathResult};
+use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
 use crate::{ResolutionError, Resolver, Segment, UseError};
 
 use rustc_ast::ptr::P;
@@ -487,6 +487,7 @@ fn visit_ty(&mut self, ty: &'ast Ty) {
                         self_ty,
                         TypeNS,
                         Finalize::SimplePath(ty.id, ty.span),
+                        None,
                     )
                     .map_or(Res::Err, |d| d.res());
                 self.r.record_partial_res(ty.id, PartialRes::new(res));
@@ -676,12 +677,8 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) {
                     // checking.
                     if path.segments.len() == 1 && path.segments[0].args.is_none() {
                         let mut check_ns = |ns| {
-                            self.resolve_ident_in_lexical_scope(
-                                path.segments[0].ident,
-                                ns,
-                                Finalize::No,
-                            )
-                            .is_some()
+                            self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
+                                .is_some()
                         };
                         if !check_ns(TypeNS) && check_ns(ValueNS) {
                             // This must be equivalent to `visit_anon_const`, but we cannot call it
@@ -750,11 +747,27 @@ fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> {
         }
     }
 
+    fn maybe_resolve_ident_in_lexical_scope(
+        &mut self,
+        ident: Ident,
+        ns: Namespace,
+    ) -> Option<LexicalScopeBinding<'a>> {
+        self.r.resolve_ident_in_lexical_scope(
+            ident,
+            ns,
+            &self.parent_scope,
+            Finalize::No,
+            &self.ribs[ns],
+            None,
+        )
+    }
+
     fn resolve_ident_in_lexical_scope(
         &mut self,
         ident: Ident,
         ns: Namespace,
         finalize: Finalize,
+        unusable_binding: Option<&'a NameBinding<'a>>,
     ) -> Option<LexicalScopeBinding<'a>> {
         self.r.resolve_ident_in_lexical_scope(
             ident,
@@ -762,6 +775,7 @@ fn resolve_ident_in_lexical_scope(
             &self.parent_scope,
             finalize,
             &self.ribs[ns],
+            unusable_binding,
         )
     }
 
@@ -771,7 +785,14 @@ fn resolve_path(
         opt_ns: Option<Namespace>, // `None` indicates a module path in import
         finalize: Finalize,
     ) -> PathResult<'a> {
-        self.r.resolve_path_with_ribs(path, opt_ns, &self.parent_scope, finalize, Some(&self.ribs))
+        self.r.resolve_path_with_ribs(
+            path,
+            opt_ns,
+            &self.parent_scope,
+            finalize,
+            Some(&self.ribs),
+            None,
+        )
     }
 
     // AST resolution
@@ -934,19 +955,16 @@ fn future_proof_import(&mut self, use_tree: &UseTree) {
             };
 
             for &ns in nss {
-                match self.resolve_ident_in_lexical_scope(ident, ns, Finalize::No) {
+                match self.maybe_resolve_ident_in_lexical_scope(ident, ns) {
                     Some(LexicalScopeBinding::Res(..)) => {
                         report_error(self, ns);
                     }
                     Some(LexicalScopeBinding::Item(binding)) => {
-                        let orig_unusable_binding =
-                            replace(&mut self.r.unusable_binding, Some(binding));
-                        if let Some(LexicalScopeBinding::Res(..)) =
-                            self.resolve_ident_in_lexical_scope(ident, ns, Finalize::No)
+                        if let Some(LexicalScopeBinding::Res(..)) = self
+                            .resolve_ident_in_lexical_scope(ident, ns, Finalize::No, Some(binding))
                         {
                             report_error(self, ns);
                         }
-                        self.r.unusable_binding = orig_unusable_binding;
                     }
                     None => {}
                 }
@@ -1802,7 +1820,7 @@ fn try_resolve_as_non_binding(
         // also be interpreted as a path to e.g. a constant, variant, etc.
         let is_syntactic_ambiguity = !has_sub && bm == BindingMode::ByValue(Mutability::Not);
 
-        let ls_binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, Finalize::No)?;
+        let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?;
         let (res, binding) = match ls_binding {
             LexicalScopeBinding::Item(binding)
                 if is_syntactic_ambiguity && binding.is_ambiguity() =>
@@ -1870,6 +1888,15 @@ fn try_resolve_as_non_binding(
                 // These entities are explicitly allowed to be shadowed by fresh bindings.
                 None
             }
+            Res::SelfCtor(_) => {
+                // We resolve `Self` in pattern position as an ident sometimes during recovery,
+                // so delay a bug instead of ICEing.
+                self.r.session.delay_span_bug(
+                    ident.span,
+                    "unexpected `SelfCtor` in pattern, expected identifier"
+                );
+                None
+            }
             _ => span_bug!(
                 ident.span,
                 "unexpected resolution for an identifier in pattern: {:?}",
@@ -2071,17 +2098,14 @@ fn smart_resolve_path_fragment(
     }
 
     fn self_type_is_available(&mut self) -> bool {
-        let binding = self.resolve_ident_in_lexical_scope(
-            Ident::with_dummy_span(kw::SelfUpper),
-            TypeNS,
-            Finalize::No,
-        );
+        let binding = self
+            .maybe_resolve_ident_in_lexical_scope(Ident::with_dummy_span(kw::SelfUpper), TypeNS);
         if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
     }
 
     fn self_value_is_available(&mut self, self_span: Span) -> bool {
         let ident = Ident::new(kw::SelfLower, self_span);
-        let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, Finalize::No);
+        let binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS);
         if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
     }
 
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 3ec63d1..0926f24 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1271,12 +1271,11 @@ fn extract_node_id(t: &Ty) -> Option<NodeId> {
 
         // Look for associated items in the current trait.
         if let Some((module, _)) = self.current_trait_ref {
-            if let Ok(binding) = self.r.resolve_ident_in_module(
+            if let Ok(binding) = self.r.maybe_resolve_ident_in_module(
                 ModuleOrUniformRoot::Module(module),
                 ident,
                 ns,
                 &self.parent_scope,
-                None,
             ) {
                 let res = binding.res();
                 if filter_fn(res) {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index a09a225..b2c7a4d 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1,5 +1,3 @@
-// ignore-tidy-filelength
-
 //! This crate is responsible for the part of name resolution that doesn't require type checker.
 //!
 //! Module structure of the crate is built here.
@@ -26,27 +24,18 @@
 
 pub use rustc_hir::def::{Namespace, PerNS};
 
-use Determinacy::*;
-
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::node_id::NodeMap;
-use rustc_ast::ptr::P;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{self as ast, NodeId};
-use rustc_ast::{Crate, CRATE_NODE_ID};
-use rustc_ast::{Expr, ExprKind, LitKind};
-use rustc_ast::{ItemKind, ModKind, Path};
+use rustc_ast::{self as ast, NodeId, CRATE_NODE_ID};
+use rustc_ast::{Crate, Expr, ExprKind, LitKind, Path};
 use rustc_ast_lowering::ResolverAstLowering;
-use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{
-    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
 use rustc_hir::def::Namespace::*;
-use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
+use rustc_hir::def::{self, CtorOf, DefKind, PartialRes};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefPathHash, LocalDefId};
 use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
@@ -55,16 +44,14 @@
 use rustc_metadata::creader::{CStore, CrateLoader};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
-use rustc_middle::{bug, span_bug};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
-use rustc_session::lint;
-use rustc_session::lint::{BuiltinLintDiagnostics, LintBuffer};
+use rustc_session::lint::LintBuffer;
 use rustc_session::Session;
-use rustc_span::edition::Edition;
-use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, Transparency};
+use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -75,10 +62,9 @@
 use std::{cmp, fmt, mem, ptr};
 use tracing::debug;
 
-use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
 use imports::{Import, ImportKind, ImportResolver, NameResolution};
-use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*};
+use late::{HasGenericParams, PathSource};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
 use crate::access_levels::AccessLevelsVisitor;
@@ -90,6 +76,7 @@
 mod check_unused;
 mod def_collector;
 mod diagnostics;
+mod ident;
 mod imports;
 mod late;
 mod macros;
@@ -315,73 +302,6 @@ fn from(seg: &'a ast::PathSegment) -> Segment {
     }
 }
 
-#[derive(Debug)]
-struct UsePlacementFinder {
-    target_module: NodeId,
-    first_legal_span: Option<Span>,
-    first_use_span: Option<Span>,
-}
-
-impl UsePlacementFinder {
-    fn check(krate: &Crate, target_module: NodeId) -> (Option<Span>, bool) {
-        let mut finder =
-            UsePlacementFinder { target_module, first_legal_span: None, first_use_span: None };
-        finder.visit_crate(krate);
-        if let Some(use_span) = finder.first_use_span {
-            (Some(use_span), true)
-        } else {
-            (finder.first_legal_span, false)
-        }
-    }
-}
-
-fn is_span_suitable_for_use_injection(s: Span) -> bool {
-    // don't suggest placing a use before the prelude
-    // import or other generated ones
-    !s.from_expansion()
-}
-
-fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> {
-    for item in items {
-        if let ItemKind::Use(..) = item.kind {
-            if is_span_suitable_for_use_injection(item.span) {
-                return Some(item.span.shrink_to_lo());
-            }
-        }
-    }
-    return None;
-}
-
-impl<'tcx> Visitor<'tcx> for UsePlacementFinder {
-    fn visit_crate(&mut self, c: &Crate) {
-        if self.target_module == CRATE_NODE_ID {
-            let inject = c.spans.inject_use_span;
-            if is_span_suitable_for_use_injection(inject) {
-                self.first_legal_span = Some(inject);
-            }
-            self.first_use_span = search_for_any_use_in_items(&c.items);
-            return;
-        } else {
-            visit::walk_crate(self, c);
-        }
-    }
-
-    fn visit_item(&mut self, item: &'tcx ast::Item) {
-        if self.target_module == item.id {
-            if let ItemKind::Mod(_, ModKind::Loaded(items, _inline, mod_spans)) = &item.kind {
-                let inject = mod_spans.inject_use_span;
-                if is_span_suitable_for_use_injection(inject) {
-                    self.first_legal_span = Some(inject);
-                }
-                self.first_use_span = search_for_any_use_in_items(items);
-                return;
-            }
-        } else {
-            visit::walk_item(self, item);
-        }
-    }
-}
-
 /// An intermediate resolution result.
 ///
 /// This refers to the thing referred by a name. The difference between `Res` and `Item` is that
@@ -928,13 +848,6 @@ pub struct Resolver<'a> {
     /// All non-determined imports.
     indeterminate_imports: Vec<&'a Import<'a>>,
 
-    /// FIXME: Refactor things so that these fields are passed through arguments and not resolver.
-    /// We are resolving a last import segment during import validation.
-    last_import_segment: bool,
-    /// This binding should be ignored during in-module resolution, so that we don't get
-    /// "self-confirming" import resolutions during import validation.
-    unusable_binding: Option<&'a NameBinding<'a>>,
-
     // Spans for local variables found during pattern resolution.
     // Used for suggestions during error reporting.
     pat_span_map: NodeMap<Span>,
@@ -1342,9 +1255,6 @@ pub fn new(
             determined_imports: Vec::new(),
             indeterminate_imports: Vec::new(),
 
-            last_import_segment: false,
-            unusable_binding: None,
-
             pat_span_map: Default::default(),
             partial_res_map: Default::default(),
             import_res_map: Default::default(),
@@ -1731,387 +1641,6 @@ fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
         }
     }
 
-    /// A generic scope visitor.
-    /// Visits scopes in order to resolve some identifier in them or perform other actions.
-    /// If the callback returns `Some` result, we stop visiting scopes and return it.
-    fn visit_scopes<T>(
-        &mut self,
-        scope_set: ScopeSet<'a>,
-        parent_scope: &ParentScope<'a>,
-        ctxt: SyntaxContext,
-        mut visitor: impl FnMut(
-            &mut Self,
-            Scope<'a>,
-            /*use_prelude*/ bool,
-            SyntaxContext,
-        ) -> Option<T>,
-    ) -> Option<T> {
-        // General principles:
-        // 1. Not controlled (user-defined) names should have higher priority than controlled names
-        //    built into the language or standard library. This way we can add new names into the
-        //    language or standard library without breaking user code.
-        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
-        // Places to search (in order of decreasing priority):
-        // (Type NS)
-        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Extern prelude (open, the open part is from macro expansions, not controlled).
-        // 4. Tool modules (closed, controlled right now, but not in the future).
-        // 5. Standard library prelude (de-facto closed, controlled).
-        // 6. Language prelude (closed, controlled).
-        // (Value NS)
-        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Standard library prelude (de-facto closed, controlled).
-        // (Macro NS)
-        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
-        //    are currently reported as errors. They should be higher in priority than preludes
-        //    and probably even names in modules according to the "general principles" above. They
-        //    also should be subject to restricted shadowing because are effectively produced by
-        //    derives (you need to resolve the derive first to add helpers into scope), but they
-        //    should be available before the derive is expanded for compatibility.
-        //    It's mess in general, so we are being conservative for now.
-        // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher
-        //    priority than prelude macros, but create ambiguities with macros in modules.
-        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled). Have higher priority than prelude macros, but create
-        //    ambiguities with `macro_rules`.
-        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
-        // 4a. User-defined prelude from macro-use
-        //    (open, the open part is from macro expansions, not controlled).
-        // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled).
-        // 4c. Standard library prelude (de-facto closed, controlled).
-        // 6. Language prelude: builtin attributes (closed, controlled).
-
-        let rust_2015 = ctxt.edition() == Edition::Edition2015;
-        let (ns, macro_kind, is_absolute_path) = match scope_set {
-            ScopeSet::All(ns, _) => (ns, None, false),
-            ScopeSet::AbsolutePath(ns) => (ns, None, true),
-            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
-            ScopeSet::Late(ns, ..) => (ns, None, false),
-        };
-        let module = match scope_set {
-            // Start with the specified module.
-            ScopeSet::Late(_, module, _) => module,
-            // Jump out of trait or enum modules, they do not act as scopes.
-            _ => parent_scope.module.nearest_item_scope(),
-        };
-        let mut scope = match ns {
-            _ if is_absolute_path => Scope::CrateRoot,
-            TypeNS | ValueNS => Scope::Module(module, None),
-            MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
-        };
-        let mut ctxt = ctxt.normalize_to_macros_2_0();
-        let mut use_prelude = !module.no_implicit_prelude;
-
-        loop {
-            let visit = match scope {
-                // Derive helpers are not in scope when resolving derives in the same container.
-                Scope::DeriveHelpers(expn_id) => {
-                    !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive))
-                }
-                Scope::DeriveHelpersCompat => true,
-                Scope::MacroRules(macro_rules_scope) => {
-                    // Use "path compression" on `macro_rules` scope chains. This is an optimization
-                    // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
-                    // As another consequence of this optimization visitors never observe invocation
-                    // scopes for macros that were already expanded.
-                    while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() {
-                        if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) {
-                            macro_rules_scope.set(next_scope.get());
-                        } else {
-                            break;
-                        }
-                    }
-                    true
-                }
-                Scope::CrateRoot => true,
-                Scope::Module(..) => true,
-                Scope::RegisteredAttrs => use_prelude,
-                Scope::MacroUsePrelude => use_prelude || rust_2015,
-                Scope::BuiltinAttrs => true,
-                Scope::ExternPrelude => use_prelude || is_absolute_path,
-                Scope::ToolPrelude => use_prelude,
-                Scope::StdLibPrelude => use_prelude || ns == MacroNS,
-                Scope::BuiltinTypes => true,
-            };
-
-            if visit {
-                if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) {
-                    return break_result;
-                }
-            }
-
-            scope = match scope {
-                Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat,
-                Scope::DeriveHelpers(expn_id) => {
-                    // Derive helpers are not visible to code generated by bang or derive macros.
-                    let expn_data = expn_id.expn_data();
-                    match expn_data.kind {
-                        ExpnKind::Root
-                        | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
-                            Scope::DeriveHelpersCompat
-                        }
-                        _ => Scope::DeriveHelpers(expn_data.parent.expect_local()),
-                    }
-                }
-                Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules),
-                Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
-                    MacroRulesScope::Binding(binding) => {
-                        Scope::MacroRules(binding.parent_macro_rules_scope)
-                    }
-                    MacroRulesScope::Invocation(invoc_id) => {
-                        Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
-                    }
-                    MacroRulesScope::Empty => Scope::Module(module, None),
-                },
-                Scope::CrateRoot => match ns {
-                    TypeNS => {
-                        ctxt.adjust(ExpnId::root());
-                        Scope::ExternPrelude
-                    }
-                    ValueNS | MacroNS => break,
-                },
-                Scope::Module(module, prev_lint_id) => {
-                    use_prelude = !module.no_implicit_prelude;
-                    let derive_fallback_lint_id = match scope_set {
-                        ScopeSet::Late(.., lint_id) => lint_id,
-                        _ => None,
-                    };
-                    match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
-                        Some((parent_module, lint_id)) => {
-                            Scope::Module(parent_module, lint_id.or(prev_lint_id))
-                        }
-                        None => {
-                            ctxt.adjust(ExpnId::root());
-                            match ns {
-                                TypeNS => Scope::ExternPrelude,
-                                ValueNS => Scope::StdLibPrelude,
-                                MacroNS => Scope::RegisteredAttrs,
-                            }
-                        }
-                    }
-                }
-                Scope::RegisteredAttrs => Scope::MacroUsePrelude,
-                Scope::MacroUsePrelude => Scope::StdLibPrelude,
-                Scope::BuiltinAttrs => break, // nowhere else to search
-                Scope::ExternPrelude if is_absolute_path => break,
-                Scope::ExternPrelude => Scope::ToolPrelude,
-                Scope::ToolPrelude => Scope::StdLibPrelude,
-                Scope::StdLibPrelude => match ns {
-                    TypeNS => Scope::BuiltinTypes,
-                    ValueNS => break, // nowhere else to search
-                    MacroNS => Scope::BuiltinAttrs,
-                },
-                Scope::BuiltinTypes => break, // nowhere else to search
-            };
-        }
-
-        None
-    }
-
-    /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
-    /// More specifically, we proceed up the hierarchy of scopes and return the binding for
-    /// `ident` in the first scope that defines it (or None if no scopes define it).
-    ///
-    /// A block's items are above its local variables in the scope hierarchy, regardless of where
-    /// the items are defined in the block. For example,
-    /// ```rust
-    /// fn f() {
-    ///    g(); // Since there are no local variables in scope yet, this resolves to the item.
-    ///    let g = || {};
-    ///    fn g() {}
-    ///    g(); // This resolves to the local variable `g` since it shadows the item.
-    /// }
-    /// ```
-    ///
-    /// Invariant: This must only be called during main resolution, not during
-    /// import resolution.
-    fn resolve_ident_in_lexical_scope(
-        &mut self,
-        mut ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
-        ribs: &[Rib<'a>],
-    ) -> Option<LexicalScopeBinding<'a>> {
-        assert!(ns == TypeNS || ns == ValueNS);
-        let orig_ident = ident;
-        if ident.name == kw::Empty {
-            return Some(LexicalScopeBinding::Res(Res::Err));
-        }
-        let (general_span, normalized_span) = if ident.name == kw::SelfUpper {
-            // FIXME(jseyfried) improve `Self` hygiene
-            let empty_span = ident.span.with_ctxt(SyntaxContext::root());
-            (empty_span, empty_span)
-        } else if ns == TypeNS {
-            let normalized_span = ident.span.normalize_to_macros_2_0();
-            (normalized_span, normalized_span)
-        } else {
-            (ident.span.normalize_to_macro_rules(), ident.span.normalize_to_macros_2_0())
-        };
-        ident.span = general_span;
-        let normalized_ident = Ident { span: normalized_span, ..ident };
-
-        // Walk backwards up the ribs in scope.
-        let finalize = finalize_full.path_span();
-        let mut module = self.graph_root;
-        for i in (0..ribs.len()).rev() {
-            debug!("walk rib\n{:?}", ribs[i].bindings);
-            // Use the rib kind to determine whether we are resolving parameters
-            // (macro 2.0 hygiene) or local variables (`macro_rules` hygiene).
-            let rib_ident = if ribs[i].kind.contains_params() { normalized_ident } else { ident };
-            if let Some((original_rib_ident_def, res)) = ribs[i].bindings.get_key_value(&rib_ident)
-            {
-                // The ident resolves to a type parameter or local variable.
-                return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs(
-                    i,
-                    rib_ident,
-                    *res,
-                    finalize,
-                    *original_rib_ident_def,
-                    ribs,
-                )));
-            }
-
-            module = match ribs[i].kind {
-                ModuleRibKind(module) => module,
-                MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
-                    // If an invocation of this macro created `ident`, give up on `ident`
-                    // and switch to `ident`'s source from the macro definition.
-                    ident.span.remove_mark();
-                    continue;
-                }
-                _ => continue,
-            };
-
-            match module.kind {
-                ModuleKind::Block(..) => {} // We can see through blocks
-                _ => break,
-            }
-
-            let item = self.resolve_ident_in_module_unadjusted(
-                ModuleOrUniformRoot::Module(module),
-                ident,
-                ns,
-                parent_scope,
-                finalize,
-            );
-            if let Ok(binding) = item {
-                // The ident resolves to an item.
-                return Some(LexicalScopeBinding::Item(binding));
-            }
-        }
-        self.early_resolve_ident_in_lexical_scope(
-            orig_ident,
-            ScopeSet::Late(ns, module, finalize_full.node_id()),
-            parent_scope,
-            finalize,
-            finalize.is_some(),
-        )
-        .ok()
-        .map(LexicalScopeBinding::Item)
-    }
-
-    fn hygienic_lexical_parent(
-        &mut self,
-        module: Module<'a>,
-        ctxt: &mut SyntaxContext,
-        derive_fallback_lint_id: Option<NodeId>,
-    ) -> Option<(Module<'a>, Option<NodeId>)> {
-        if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
-            return Some((self.expn_def_scope(ctxt.remove_mark()), None));
-        }
-
-        if let ModuleKind::Block(..) = module.kind {
-            return Some((module.parent.unwrap().nearest_item_scope(), None));
-        }
-
-        // We need to support the next case under a deprecation warning
-        // ```
-        // struct MyStruct;
-        // ---- begin: this comes from a proc macro derive
-        // mod implementation_details {
-        //     // Note that `MyStruct` is not in scope here.
-        //     impl SomeTrait for MyStruct { ... }
-        // }
-        // ---- end
-        // ```
-        // So we have to fall back to the module's parent during lexical resolution in this case.
-        if derive_fallback_lint_id.is_some() {
-            if let Some(parent) = module.parent {
-                // Inner module is inside the macro, parent module is outside of the macro.
-                if module.expansion != parent.expansion
-                    && module.expansion.is_descendant_of(parent.expansion)
-                {
-                    // The macro is a proc macro derive
-                    if let Some(def_id) = module.expansion.expn_data().macro_def_id {
-                        let ext = self.get_macro_by_def_id(def_id);
-                        if ext.builtin_name.is_none()
-                            && ext.macro_kind() == MacroKind::Derive
-                            && parent.expansion.outer_expn_is_descendant_of(*ctxt)
-                        {
-                            return Some((parent, derive_fallback_lint_id));
-                        }
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    fn resolve_ident_in_module(
-        &mut self,
-        module: ModuleOrUniformRoot<'a>,
-        ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-    ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        self.resolve_ident_in_module_ext(module, ident, ns, parent_scope, finalize)
-            .map_err(|(determinacy, _)| determinacy)
-    }
-
-    fn resolve_ident_in_module_ext(
-        &mut self,
-        module: ModuleOrUniformRoot<'a>,
-        mut ident: Ident,
-        ns: Namespace,
-        parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-    ) -> Result<&'a NameBinding<'a>, (Determinacy, Weak)> {
-        let tmp_parent_scope;
-        let mut adjusted_parent_scope = parent_scope;
-        match module {
-            ModuleOrUniformRoot::Module(m) => {
-                if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) {
-                    tmp_parent_scope =
-                        ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
-                    adjusted_parent_scope = &tmp_parent_scope;
-                }
-            }
-            ModuleOrUniformRoot::ExternPrelude => {
-                ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root());
-            }
-            ModuleOrUniformRoot::CrateRootAndExternPrelude | ModuleOrUniformRoot::CurrentScope => {
-                // No adjustments
-            }
-        }
-        self.resolve_ident_in_module_unadjusted_ext(
-            module,
-            ident,
-            ns,
-            adjusted_parent_scope,
-            false,
-            finalize,
-        )
-    }
-
     fn resolve_crate_root(&mut self, ident: Ident) -> Module<'a> {
         debug!("resolve_crate_root({:?})", ident);
         let mut ctxt = ident.span.ctxt();
@@ -2194,676 +1723,6 @@ fn resolve_self(&mut self, ctxt: &mut SyntaxContext, module: Module<'a>) -> Modu
         module
     }
 
-    fn resolve_path(
-        &mut self,
-        path: &[Segment],
-        opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        parent_scope: &ParentScope<'a>,
-        finalize: Finalize,
-    ) -> PathResult<'a> {
-        self.resolve_path_with_ribs(path, opt_ns, parent_scope, finalize, None)
-    }
-
-    fn resolve_path_with_ribs(
-        &mut self,
-        path: &[Segment],
-        opt_ns: Option<Namespace>, // `None` indicates a module path in import
-        parent_scope: &ParentScope<'a>,
-        finalize_full: Finalize,
-        ribs: Option<&PerNS<Vec<Rib<'a>>>>,
-    ) -> PathResult<'a> {
-        debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize_full);
-
-        let finalize = finalize_full.path_span();
-        let mut module = None;
-        let mut allow_super = true;
-        let mut second_binding = None;
-
-        for (i, &Segment { ident, id, has_generic_args: _ }) in path.iter().enumerate() {
-            debug!("resolve_path ident {} {:?} {:?}", i, ident, id);
-            let record_segment_res = |this: &mut Self, res| {
-                if finalize.is_some() {
-                    if let Some(id) = id {
-                        if !this.partial_res_map.contains_key(&id) {
-                            assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id");
-                            this.record_partial_res(id, PartialRes::new(res));
-                        }
-                    }
-                }
-            };
-
-            let is_last = i == path.len() - 1;
-            let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
-            let name = ident.name;
-
-            allow_super &= ns == TypeNS && (name == kw::SelfLower || name == kw::Super);
-
-            if ns == TypeNS {
-                if allow_super && name == kw::Super {
-                    let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
-                    let self_module = match i {
-                        0 => Some(self.resolve_self(&mut ctxt, parent_scope.module)),
-                        _ => match module {
-                            Some(ModuleOrUniformRoot::Module(module)) => Some(module),
-                            _ => None,
-                        },
-                    };
-                    if let Some(self_module) = self_module {
-                        if let Some(parent) = self_module.parent {
-                            module = Some(ModuleOrUniformRoot::Module(
-                                self.resolve_self(&mut ctxt, parent),
-                            ));
-                            continue;
-                        }
-                    }
-                    return PathResult::failed(ident.span, false, finalize.is_some(), || {
-                        ("there are too many leading `super` keywords".to_string(), None)
-                    });
-                }
-                if i == 0 {
-                    if name == kw::SelfLower {
-                        let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0();
-                        module = Some(ModuleOrUniformRoot::Module(
-                            self.resolve_self(&mut ctxt, parent_scope.module),
-                        ));
-                        continue;
-                    }
-                    if name == kw::PathRoot && ident.span.rust_2018() {
-                        module = Some(ModuleOrUniformRoot::ExternPrelude);
-                        continue;
-                    }
-                    if name == kw::PathRoot && ident.span.rust_2015() && self.session.rust_2018() {
-                        // `::a::b` from 2015 macro on 2018 global edition
-                        module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
-                        continue;
-                    }
-                    if name == kw::PathRoot || name == kw::Crate || name == kw::DollarCrate {
-                        // `::a::b`, `crate::a::b` or `$crate::a::b`
-                        module = Some(ModuleOrUniformRoot::Module(self.resolve_crate_root(ident)));
-                        continue;
-                    }
-                }
-            }
-
-            // Report special messages for path segment keywords in wrong positions.
-            if ident.is_path_segment_keyword() && i != 0 {
-                return PathResult::failed(ident.span, false, finalize.is_some(), || {
-                    let name_str = if name == kw::PathRoot {
-                        "crate root".to_string()
-                    } else {
-                        format!("`{}`", name)
-                    };
-                    let label = if i == 1 && path[0].ident.name == kw::PathRoot {
-                        format!("global paths cannot start with {}", name_str)
-                    } else {
-                        format!("{} in paths can only be used in start position", name_str)
-                    };
-                    (label, None)
-                });
-            }
-
-            enum FindBindingResult<'a> {
-                Binding(Result<&'a NameBinding<'a>, Determinacy>),
-                PathResult(PathResult<'a>),
-            }
-            let find_binding_in_ns = |this: &mut Self, ns| {
-                let binding = if let Some(module) = module {
-                    this.resolve_ident_in_module(module, ident, ns, parent_scope, finalize)
-                } else if ribs.is_none() || opt_ns.is_none() || opt_ns == Some(MacroNS) {
-                    let scopes = ScopeSet::All(ns, opt_ns.is_none());
-                    this.early_resolve_ident_in_lexical_scope(
-                        ident,
-                        scopes,
-                        parent_scope,
-                        finalize,
-                        finalize.is_some(),
-                    )
-                } else {
-                    match this.resolve_ident_in_lexical_scope(
-                        ident,
-                        ns,
-                        parent_scope,
-                        finalize_full,
-                        &ribs.unwrap()[ns],
-                    ) {
-                        // we found a locally-imported or available item/module
-                        Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
-                        // we found a local variable or type param
-                        Some(LexicalScopeBinding::Res(res))
-                            if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) =>
-                        {
-                            record_segment_res(this, res);
-                            return FindBindingResult::PathResult(PathResult::NonModule(
-                                PartialRes::with_unresolved_segments(res, path.len() - 1),
-                            ));
-                        }
-                        _ => Err(Determinacy::determined(finalize.is_some())),
-                    }
-                };
-                FindBindingResult::Binding(binding)
-            };
-            let binding = match find_binding_in_ns(self, ns) {
-                FindBindingResult::PathResult(x) => return x,
-                FindBindingResult::Binding(binding) => binding,
-            };
-            match binding {
-                Ok(binding) => {
-                    if i == 1 {
-                        second_binding = Some(binding);
-                    }
-                    let res = binding.res();
-                    let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
-                    if let Some(next_module) = binding.module() {
-                        module = Some(ModuleOrUniformRoot::Module(next_module));
-                        record_segment_res(self, res);
-                    } else if res == Res::ToolMod && i + 1 != path.len() {
-                        if binding.is_import() {
-                            self.session
-                                .struct_span_err(
-                                    ident.span,
-                                    "cannot use a tool module through an import",
-                                )
-                                .span_note(binding.span, "the tool module imported here")
-                                .emit();
-                        }
-                        let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
-                        return PathResult::NonModule(PartialRes::new(res));
-                    } else if res == Res::Err {
-                        return PathResult::NonModule(PartialRes::new(Res::Err));
-                    } else if opt_ns.is_some() && (is_last || maybe_assoc) {
-                        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
-                        return PathResult::NonModule(PartialRes::with_unresolved_segments(
-                            res,
-                            path.len() - i - 1,
-                        ));
-                    } else {
-                        return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
-                            let label = format!(
-                                "`{ident}` is {} {}, not a module",
-                                res.article(),
-                                res.descr()
-                            );
-                            (label, None)
-                        });
-                    }
-                }
-                Err(Undetermined) => return PathResult::Indeterminate,
-                Err(Determined) => {
-                    if let Some(ModuleOrUniformRoot::Module(module)) = module {
-                        if opt_ns.is_some() && !module.is_normal() {
-                            return PathResult::NonModule(PartialRes::with_unresolved_segments(
-                                module.res().unwrap(),
-                                path.len() - i,
-                            ));
-                        }
-                    }
-
-                    return PathResult::failed(ident.span, is_last, finalize.is_some(), || {
-                        let module_res = match module {
-                            Some(ModuleOrUniformRoot::Module(module)) => module.res(),
-                            _ => None,
-                        };
-                        if module_res == self.graph_root.res() {
-                            let is_mod = |res| matches!(res, Res::Def(DefKind::Mod, _));
-                            let mut candidates =
-                                self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod);
-                            candidates.sort_by_cached_key(|c| {
-                                (c.path.segments.len(), pprust::path_to_string(&c.path))
-                            });
-                            if let Some(candidate) = candidates.get(0) {
-                                (
-                                    String::from("unresolved import"),
-                                    Some((
-                                        vec![(ident.span, pprust::path_to_string(&candidate.path))],
-                                        String::from("a similar path exists"),
-                                        Applicability::MaybeIncorrect,
-                                    )),
-                                )
-                            } else if self.session.edition() == Edition::Edition2015 {
-                                (format!("maybe a missing crate `{}`?", ident), None)
-                            } else {
-                                (format!("could not find `{}` in the crate root", ident), None)
-                            }
-                        } else if i == 0 {
-                            if ident
-                                .name
-                                .as_str()
-                                .chars()
-                                .next()
-                                .map_or(false, |c| c.is_ascii_uppercase())
-                            {
-                                // Check whether the name refers to an item in the value namespace.
-                                let suggestion = if ribs.is_some() {
-                                    let match_span = match self.resolve_ident_in_lexical_scope(
-                                        ident,
-                                        ValueNS,
-                                        parent_scope,
-                                        Finalize::No,
-                                        &ribs.unwrap()[ValueNS],
-                                    ) {
-                                        // Name matches a local variable. For example:
-                                        // ```
-                                        // fn f() {
-                                        //     let Foo: &str = "";
-                                        //     println!("{}", Foo::Bar); // Name refers to local
-                                        //                               // variable `Foo`.
-                                        // }
-                                        // ```
-                                        Some(LexicalScopeBinding::Res(Res::Local(id))) => {
-                                            Some(*self.pat_span_map.get(&id).unwrap())
-                                        }
-
-                                        // Name matches item from a local name binding
-                                        // created by `use` declaration. For example:
-                                        // ```
-                                        // pub Foo: &str = "";
-                                        //
-                                        // mod submod {
-                                        //     use super::Foo;
-                                        //     println!("{}", Foo::Bar); // Name refers to local
-                                        //                               // binding `Foo`.
-                                        // }
-                                        // ```
-                                        Some(LexicalScopeBinding::Item(name_binding)) => {
-                                            Some(name_binding.span)
-                                        }
-                                        _ => None,
-                                    };
-
-                                    if let Some(span) = match_span {
-                                        Some((
-                                            vec![(span, String::from(""))],
-                                            format!(
-                                                "`{}` is defined here, but is not a type",
-                                                ident
-                                            ),
-                                            Applicability::MaybeIncorrect,
-                                        ))
-                                    } else {
-                                        None
-                                    }
-                                } else {
-                                    None
-                                };
-
-                                (format!("use of undeclared type `{}`", ident), suggestion)
-                            } else {
-                                (
-                                    format!("use of undeclared crate or module `{}`", ident),
-                                    if ident.name == sym::alloc {
-                                        Some((
-                                            vec![],
-                                            String::from(
-                                                "add `extern crate alloc` to use the `alloc` crate",
-                                            ),
-                                            Applicability::MaybeIncorrect,
-                                        ))
-                                    } else {
-                                        self.find_similarly_named_module_or_crate(
-                                            ident.name,
-                                            &parent_scope.module,
-                                        )
-                                        .map(|sugg| {
-                                            (
-                                                vec![(ident.span, sugg.to_string())],
-                                                String::from(
-                                                    "there is a crate or module with a similar name",
-                                                ),
-                                                Applicability::MaybeIncorrect,
-                                            )
-                                        })
-                                    },
-                                )
-                            }
-                        } else {
-                            let parent = path[i - 1].ident.name;
-                            let parent = match parent {
-                                // ::foo is mounted at the crate root for 2015, and is the extern
-                                // prelude for 2018+
-                                kw::PathRoot if self.session.edition() > Edition::Edition2015 => {
-                                    "the list of imported crates".to_owned()
-                                }
-                                kw::PathRoot | kw::Crate => "the crate root".to_owned(),
-                                _ => {
-                                    format!("`{}`", parent)
-                                }
-                            };
-
-                            let mut msg = format!("could not find `{}` in {}", ident, parent);
-                            if ns == TypeNS || ns == ValueNS {
-                                let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS };
-                                if let FindBindingResult::Binding(Ok(binding)) =
-                                    find_binding_in_ns(self, ns_to_try)
-                                {
-                                    let mut found = |what| {
-                                        msg = format!(
-                                            "expected {}, found {} `{}` in {}",
-                                            ns.descr(),
-                                            what,
-                                            ident,
-                                            parent
-                                        )
-                                    };
-                                    if binding.module().is_some() {
-                                        found("module")
-                                    } else {
-                                        match binding.res() {
-                                            def::Res::<NodeId>::Def(kind, id) => {
-                                                found(kind.descr(id))
-                                            }
-                                            _ => found(ns_to_try.descr()),
-                                        }
-                                    }
-                                };
-                            }
-                            (msg, None)
-                        }
-                    });
-                }
-            }
-        }
-
-        self.lint_if_path_starts_with_module(finalize_full, path, second_binding);
-
-        PathResult::Module(match module {
-            Some(module) => module,
-            None if path.is_empty() => ModuleOrUniformRoot::CurrentScope,
-            _ => bug!("resolve_path: non-empty path `{:?}` has no module", path),
-        })
-    }
-
-    fn lint_if_path_starts_with_module(
-        &mut self,
-        finalize: Finalize,
-        path: &[Segment],
-        second_binding: Option<&NameBinding<'_>>,
-    ) {
-        let (diag_id, diag_span) = match finalize {
-            Finalize::No => return,
-            Finalize::SimplePath(id, path_span) => (id, path_span),
-            Finalize::UsePath { root_id, root_span, .. } => (root_id, root_span),
-            Finalize::QPathTrait { qpath_id, qpath_span, .. } => (qpath_id, qpath_span),
-        };
-
-        let first_name = match path.get(0) {
-            // In the 2018 edition this lint is a hard error, so nothing to do
-            Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name,
-            _ => return,
-        };
-
-        // We're only interested in `use` paths which should start with
-        // `{{root}}` currently.
-        if first_name != kw::PathRoot {
-            return;
-        }
-
-        match path.get(1) {
-            // If this import looks like `crate::...` it's already good
-            Some(Segment { ident, .. }) if ident.name == kw::Crate => return,
-            // Otherwise go below to see if it's an extern crate
-            Some(_) => {}
-            // If the path has length one (and it's `PathRoot` most likely)
-            // then we don't know whether we're gonna be importing a crate or an
-            // item in our crate. Defer this lint to elsewhere
-            None => return,
-        }
-
-        // If the first element of our path was actually resolved to an
-        // `ExternCrate` (also used for `crate::...`) then no need to issue a
-        // warning, this looks all good!
-        if let Some(binding) = second_binding {
-            if let NameBindingKind::Import { import, .. } = binding.kind {
-                // Careful: we still want to rewrite paths from renamed extern crates.
-                if let ImportKind::ExternCrate { source: None, .. } = import.kind {
-                    return;
-                }
-            }
-        }
-
-        let diag = BuiltinLintDiagnostics::AbsPathWithModule(diag_span);
-        self.lint_buffer.buffer_lint_with_diagnostic(
-            lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
-            diag_id,
-            diag_span,
-            "absolute paths must start with `self`, `super`, \
-             `crate`, or an external crate name in the 2018 edition",
-            diag,
-        );
-    }
-
-    // Validate a local resolution (from ribs).
-    fn validate_res_from_ribs(
-        &mut self,
-        rib_index: usize,
-        rib_ident: Ident,
-        mut res: Res,
-        finalize: Option<Span>,
-        original_rib_ident_def: Ident,
-        all_ribs: &[Rib<'a>],
-    ) -> Res {
-        const CG_BUG_STR: &str = "min_const_generics resolve check didn't stop compilation";
-        debug!("validate_res_from_ribs({:?})", res);
-        let ribs = &all_ribs[rib_index + 1..];
-
-        // An invalid forward use of a generic parameter from a previous default.
-        if let ForwardGenericParamBanRibKind = all_ribs[rib_index].kind {
-            if let Some(span) = finalize {
-                let res_error = if rib_ident.name == kw::SelfUpper {
-                    ResolutionError::SelfInGenericParamDefault
-                } else {
-                    ResolutionError::ForwardDeclaredGenericParam
-                };
-                self.report_error(span, res_error);
-            }
-            assert_eq!(res, Res::Err);
-            return Res::Err;
-        }
-
-        match res {
-            Res::Local(_) => {
-                use ResolutionError::*;
-                let mut res_err = None;
-
-                for rib in ribs {
-                    match rib.kind {
-                        NormalRibKind
-                        | ClosureOrAsyncRibKind
-                        | ModuleRibKind(..)
-                        | MacroDefinition(..)
-                        | ForwardGenericParamBanRibKind => {
-                            // Nothing to do. Continue.
-                        }
-                        ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => {
-                            // This was an attempt to access an upvar inside a
-                            // named function item. This is not allowed, so we
-                            // report an error.
-                            if let Some(span) = finalize {
-                                // We don't immediately trigger a resolve error, because
-                                // we want certain other resolution errors (namely those
-                                // emitted for `ConstantItemRibKind` below) to take
-                                // precedence.
-                                res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem));
-                            }
-                        }
-                        ConstantItemRibKind(_, item) => {
-                            // Still doesn't deal with upvars
-                            if let Some(span) = finalize {
-                                let (span, resolution_error) =
-                                    if let Some((ident, constant_item_kind)) = item {
-                                        let kind_str = match constant_item_kind {
-                                            ConstantItemKind::Const => "const",
-                                            ConstantItemKind::Static => "static",
-                                        };
-                                        (
-                                            span,
-                                            AttemptToUseNonConstantValueInConstant(
-                                                ident, "let", kind_str,
-                                            ),
-                                        )
-                                    } else {
-                                        (
-                                            rib_ident.span,
-                                            AttemptToUseNonConstantValueInConstant(
-                                                original_rib_ident_def,
-                                                "const",
-                                                "let",
-                                            ),
-                                        )
-                                    };
-                                self.report_error(span, resolution_error);
-                            }
-                            return Res::Err;
-                        }
-                        ConstParamTyRibKind => {
-                            if let Some(span) = finalize {
-                                self.report_error(span, ParamInTyOfConstParam(rib_ident.name));
-                            }
-                            return Res::Err;
-                        }
-                    }
-                }
-                if let Some((span, res_err)) = res_err {
-                    self.report_error(span, res_err);
-                    return Res::Err;
-                }
-            }
-            Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
-                for rib in ribs {
-                    let has_generic_params: HasGenericParams = match rib.kind {
-                        NormalRibKind
-                        | ClosureOrAsyncRibKind
-                        | AssocItemRibKind
-                        | ModuleRibKind(..)
-                        | MacroDefinition(..)
-                        | ForwardGenericParamBanRibKind => {
-                            // Nothing to do. Continue.
-                            continue;
-                        }
-
-                        ConstantItemRibKind(trivial, _) => {
-                            let features = self.session.features_untracked();
-                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
-                                // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
-                                // we can't easily tell if it's generic at this stage, so we instead remember
-                                // this and then enforce the self type to be concrete later on.
-                                if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
-                                    res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
-                                } else {
-                                    if let Some(span) = finalize {
-                                        self.report_error(
-                                            span,
-                                            ResolutionError::ParamInNonTrivialAnonConst {
-                                                name: rib_ident.name,
-                                                is_type: true,
-                                            },
-                                        );
-                                        self.session.delay_span_bug(span, CG_BUG_STR);
-                                    }
-
-                                    return Res::Err;
-                                }
-                            }
-
-                            continue;
-                        }
-
-                        // This was an attempt to use a type parameter outside its scope.
-                        ItemRibKind(has_generic_params) => has_generic_params,
-                        FnItemRibKind => HasGenericParams::Yes,
-                        ConstParamTyRibKind => {
-                            if let Some(span) = finalize {
-                                self.report_error(
-                                    span,
-                                    ResolutionError::ParamInTyOfConstParam(rib_ident.name),
-                                );
-                            }
-                            return Res::Err;
-                        }
-                    };
-
-                    if let Some(span) = finalize {
-                        self.report_error(
-                            span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
-                        );
-                    }
-                    return Res::Err;
-                }
-            }
-            Res::Def(DefKind::ConstParam, _) => {
-                let mut ribs = ribs.iter().peekable();
-                if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() {
-                    // When declaring const parameters inside function signatures, the first rib
-                    // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it
-                    // (spuriously) conflicting with the const param.
-                    ribs.next();
-                }
-
-                for rib in ribs {
-                    let has_generic_params = match rib.kind {
-                        NormalRibKind
-                        | ClosureOrAsyncRibKind
-                        | AssocItemRibKind
-                        | ModuleRibKind(..)
-                        | MacroDefinition(..)
-                        | ForwardGenericParamBanRibKind => continue,
-
-                        ConstantItemRibKind(trivial, _) => {
-                            let features = self.session.features_untracked();
-                            // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
-                            if !(trivial || features.generic_const_exprs) {
-                                if let Some(span) = finalize {
-                                    self.report_error(
-                                        span,
-                                        ResolutionError::ParamInNonTrivialAnonConst {
-                                            name: rib_ident.name,
-                                            is_type: false,
-                                        },
-                                    );
-                                    self.session.delay_span_bug(span, CG_BUG_STR);
-                                }
-
-                                return Res::Err;
-                            }
-
-                            continue;
-                        }
-
-                        ItemRibKind(has_generic_params) => has_generic_params,
-                        FnItemRibKind => HasGenericParams::Yes,
-                        ConstParamTyRibKind => {
-                            if let Some(span) = finalize {
-                                self.report_error(
-                                    span,
-                                    ResolutionError::ParamInTyOfConstParam(rib_ident.name),
-                                );
-                            }
-                            return Res::Err;
-                        }
-                    };
-
-                    // This was an attempt to use a const parameter outside its scope.
-                    if let Some(span) = finalize {
-                        self.report_error(
-                            span,
-                            ResolutionError::GenericParamsFromOuterFunction(
-                                res,
-                                has_generic_params,
-                            ),
-                        );
-                    }
-                    return Res::Err;
-                }
-            }
-            _ => {}
-        }
-        res
-    }
-
     fn record_partial_res(&mut self, node_id: NodeId, resolution: PartialRes) {
         debug!("(recording res) recording {:?} for {}", resolution, node_id);
         if let Some(prev_res) = self.partial_res_map.insert(node_id, resolution) {
@@ -2910,331 +1769,6 @@ fn disambiguate_macro_rules_vs_modularized(
         }
     }
 
-    fn report_errors(&mut self, krate: &Crate) {
-        self.report_with_use_injections(krate);
-
-        for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
-            let msg = "macro-expanded `macro_export` macros from the current crate \
-                       cannot be referred to by absolute paths";
-            self.lint_buffer.buffer_lint_with_diagnostic(
-                lint::builtin::MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
-                CRATE_NODE_ID,
-                span_use,
-                msg,
-                BuiltinLintDiagnostics::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
-            );
-        }
-
-        for ambiguity_error in &self.ambiguity_errors {
-            self.report_ambiguity_error(ambiguity_error);
-        }
-
-        let mut reported_spans = FxHashSet::default();
-        for error in &self.privacy_errors {
-            if reported_spans.insert(error.dedup_span) {
-                self.report_privacy_error(error);
-            }
-        }
-    }
-
-    fn report_with_use_injections(&mut self, krate: &Crate) {
-        for UseError { mut err, candidates, def_id, instead, suggestion } in
-            self.use_injections.drain(..)
-        {
-            let (span, found_use) = if let Some(def_id) = def_id.as_local() {
-                UsePlacementFinder::check(krate, self.def_id_to_node_id[def_id])
-            } else {
-                (None, false)
-            };
-            if !candidates.is_empty() {
-                diagnostics::show_candidates(
-                    &self.definitions,
-                    self.session,
-                    &mut err,
-                    span,
-                    &candidates,
-                    instead,
-                    found_use,
-                );
-            } else if let Some((span, msg, sugg, appl)) = suggestion {
-                err.span_suggestion(span, msg, sugg, appl);
-            }
-            err.emit();
-        }
-    }
-
-    fn report_conflict<'b>(
-        &mut self,
-        parent: Module<'_>,
-        ident: Ident,
-        ns: Namespace,
-        new_binding: &NameBinding<'b>,
-        old_binding: &NameBinding<'b>,
-    ) {
-        // Error on the second of two conflicting names
-        if old_binding.span.lo() > new_binding.span.lo() {
-            return self.report_conflict(parent, ident, ns, old_binding, new_binding);
-        }
-
-        let container = match parent.kind {
-            ModuleKind::Def(kind, _, _) => kind.descr(parent.def_id()),
-            ModuleKind::Block(..) => "block",
-        };
-
-        let old_noun = match old_binding.is_import() {
-            true => "import",
-            false => "definition",
-        };
-
-        let new_participle = match new_binding.is_import() {
-            true => "imported",
-            false => "defined",
-        };
-
-        let (name, span) =
-            (ident.name, self.session.source_map().guess_head_span(new_binding.span));
-
-        if let Some(s) = self.name_already_seen.get(&name) {
-            if s == &span {
-                return;
-            }
-        }
-
-        let old_kind = match (ns, old_binding.module()) {
-            (ValueNS, _) => "value",
-            (MacroNS, _) => "macro",
-            (TypeNS, _) if old_binding.is_extern_crate() => "extern crate",
-            (TypeNS, Some(module)) if module.is_normal() => "module",
-            (TypeNS, Some(module)) if module.is_trait() => "trait",
-            (TypeNS, _) => "type",
-        };
-
-        let msg = format!("the name `{}` is defined multiple times", name);
-
-        let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
-            (true, true) => struct_span_err!(self.session, span, E0259, "{}", msg),
-            (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
-                true => struct_span_err!(self.session, span, E0254, "{}", msg),
-                false => struct_span_err!(self.session, span, E0260, "{}", msg),
-            },
-            _ => match (old_binding.is_import(), new_binding.is_import()) {
-                (false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
-                (true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
-                _ => struct_span_err!(self.session, span, E0255, "{}", msg),
-            },
-        };
-
-        err.note(&format!(
-            "`{}` must be defined only once in the {} namespace of this {}",
-            name,
-            ns.descr(),
-            container
-        ));
-
-        err.span_label(span, format!("`{}` re{} here", name, new_participle));
-        err.span_label(
-            self.session.source_map().guess_head_span(old_binding.span),
-            format!("previous {} of the {} `{}` here", old_noun, old_kind, name),
-        );
-
-        // See https://github.com/rust-lang/rust/issues/32354
-        use NameBindingKind::Import;
-        let import = match (&new_binding.kind, &old_binding.kind) {
-            // If there are two imports where one or both have attributes then prefer removing the
-            // import without attributes.
-            (Import { import: new, .. }, Import { import: old, .. })
-                if {
-                    !new_binding.span.is_dummy()
-                        && !old_binding.span.is_dummy()
-                        && (new.has_attributes || old.has_attributes)
-                } =>
-            {
-                if old.has_attributes {
-                    Some((new, new_binding.span, true))
-                } else {
-                    Some((old, old_binding.span, true))
-                }
-            }
-            // Otherwise prioritize the new binding.
-            (Import { import, .. }, other) if !new_binding.span.is_dummy() => {
-                Some((import, new_binding.span, other.is_import()))
-            }
-            (other, Import { import, .. }) if !old_binding.span.is_dummy() => {
-                Some((import, old_binding.span, other.is_import()))
-            }
-            _ => None,
-        };
-
-        // Check if the target of the use for both bindings is the same.
-        let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id();
-        let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy();
-        let from_item =
-            self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item);
-        // Only suggest removing an import if both bindings are to the same def, if both spans
-        // aren't dummy spans. Further, if both bindings are imports, then the ident must have
-        // been introduced by an item.
-        let should_remove_import = duplicate
-            && !has_dummy_span
-            && ((new_binding.is_extern_crate() || old_binding.is_extern_crate()) || from_item);
-
-        match import {
-            Some((import, span, true)) if should_remove_import && import.is_nested() => {
-                self.add_suggestion_for_duplicate_nested_use(&mut err, import, span)
-            }
-            Some((import, _, true)) if should_remove_import && !import.is_glob() => {
-                // Simple case - remove the entire import. Due to the above match arm, this can
-                // only be a single use so just remove it entirely.
-                err.tool_only_span_suggestion(
-                    import.use_span_with_attributes,
-                    "remove unnecessary import",
-                    String::new(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-            Some((import, span, _)) => {
-                self.add_suggestion_for_rename_of_use(&mut err, name, import, span)
-            }
-            _ => {}
-        }
-
-        err.emit();
-        self.name_already_seen.insert(name, span);
-    }
-
-    /// This function adds a suggestion to change the binding name of a new import that conflicts
-    /// with an existing import.
-    ///
-    /// ```text,ignore (diagnostic)
-    /// help: you can use `as` to change the binding name of the import
-    ///    |
-    /// LL | use foo::bar as other_bar;
-    ///    |     ^^^^^^^^^^^^^^^^^^^^^
-    /// ```
-    fn add_suggestion_for_rename_of_use(
-        &self,
-        err: &mut Diagnostic,
-        name: Symbol,
-        import: &Import<'_>,
-        binding_span: Span,
-    ) {
-        let suggested_name = if name.as_str().chars().next().unwrap().is_uppercase() {
-            format!("Other{}", name)
-        } else {
-            format!("other_{}", name)
-        };
-
-        let mut suggestion = None;
-        match import.kind {
-            ImportKind::Single { type_ns_only: true, .. } => {
-                suggestion = Some(format!("self as {}", suggested_name))
-            }
-            ImportKind::Single { source, .. } => {
-                if let Some(pos) =
-                    source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize)
-                {
-                    if let Ok(snippet) = self.session.source_map().span_to_snippet(binding_span) {
-                        if pos <= snippet.len() {
-                            suggestion = Some(format!(
-                                "{} as {}{}",
-                                &snippet[..pos],
-                                suggested_name,
-                                if snippet.ends_with(';') { ";" } else { "" }
-                            ))
-                        }
-                    }
-                }
-            }
-            ImportKind::ExternCrate { source, target } => {
-                suggestion = Some(format!(
-                    "extern crate {} as {};",
-                    source.unwrap_or(target.name),
-                    suggested_name,
-                ))
-            }
-            _ => unreachable!(),
-        }
-
-        let rename_msg = "you can use `as` to change the binding name of the import";
-        if let Some(suggestion) = suggestion {
-            err.span_suggestion(
-                binding_span,
-                rename_msg,
-                suggestion,
-                Applicability::MaybeIncorrect,
-            );
-        } else {
-            err.span_label(binding_span, rename_msg);
-        }
-    }
-
-    /// This function adds a suggestion to remove an unnecessary binding from an import that is
-    /// nested. In the following example, this function will be invoked to remove the `a` binding
-    /// in the second use statement:
-    ///
-    /// ```ignore (diagnostic)
-    /// use issue_52891::a;
-    /// use issue_52891::{d, a, e};
-    /// ```
-    ///
-    /// The following suggestion will be added:
-    ///
-    /// ```ignore (diagnostic)
-    /// use issue_52891::{d, a, e};
-    ///                      ^-- help: remove unnecessary import
-    /// ```
-    ///
-    /// If the nested use contains only one import then the suggestion will remove the entire
-    /// line.
-    ///
-    /// It is expected that the provided import is nested - this isn't checked by the
-    /// function. If this invariant is not upheld, this function's behaviour will be unexpected
-    /// as characters expected by span manipulations won't be present.
-    fn add_suggestion_for_duplicate_nested_use(
-        &self,
-        err: &mut Diagnostic,
-        import: &Import<'_>,
-        binding_span: Span,
-    ) {
-        assert!(import.is_nested());
-        let message = "remove unnecessary import";
-
-        // Two examples will be used to illustrate the span manipulations we're doing:
-        //
-        // - Given `use issue_52891::{d, a, e};` where `a` is a duplicate then `binding_span` is
-        //   `a` and `import.use_span` is `issue_52891::{d, a, e};`.
-        // - Given `use issue_52891::{d, e, a};` where `a` is a duplicate then `binding_span` is
-        //   `a` and `import.use_span` is `issue_52891::{d, e, a};`.
-
-        let (found_closing_brace, span) =
-            find_span_of_binding_until_next_binding(self.session, binding_span, import.use_span);
-
-        // If there was a closing brace then identify the span to remove any trailing commas from
-        // previous imports.
-        if found_closing_brace {
-            if let Some(span) = extend_span_to_previous_binding(self.session, span) {
-                err.tool_only_span_suggestion(
-                    span,
-                    message,
-                    String::new(),
-                    Applicability::MaybeIncorrect,
-                );
-            } else {
-                // Remove the entire line if we cannot extend the span back, this indicates an
-                // `issue_52891::{self}` case.
-                err.span_suggestion(
-                    import.use_span_with_attributes,
-                    message,
-                    String::new(),
-                    Applicability::MaybeIncorrect,
-                );
-            }
-
-            return;
-        }
-
-        err.span_suggestion(span, message, String::new(), Applicability::MachineApplicable);
-    }
-
     fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<&'a NameBinding<'a>> {
         if ident.is_path_segment_keyword() {
             // Make sure `self`, `super` etc produce an error when passed to here.
@@ -3289,12 +1823,7 @@ pub fn resolve_rustdoc_path(
         }
 
         let module = self.expect_module(module_id);
-        match self.resolve_path(
-            &segments,
-            Some(ns),
-            &ParentScope::module(module, self),
-            Finalize::No,
-        ) {
+        match self.maybe_resolve_path(&segments, Some(ns), &ParentScope::module(module, self)) {
             PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()),
             PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                 Some(path_res.base_res())
@@ -3384,12 +1913,11 @@ fn resolve_main(&mut self) {
         let ident = Ident::with_dummy_span(sym::main);
         let parent_scope = &ParentScope::module(module, self);
 
-        let Ok(name_binding) = self.resolve_ident_in_module(
+        let Ok(name_binding) = self.maybe_resolve_ident_in_module(
             ModuleOrUniformRoot::Module(module),
             ident,
             ValueNS,
             parent_scope,
-            None
         ) else {
             return;
         };
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 3a90908..01f0b11 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -3,9 +3,9 @@
 
 use crate::imports::ImportResolver;
 use crate::Namespace::*;
-use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy};
-use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak};
-use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding};
+use crate::{BuiltinMacroState, Determinacy};
+use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
+use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment};
 use rustc_ast::{self as ast, Inline, ItemKind, ModKind, NodeId};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
@@ -18,14 +18,11 @@
 use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind};
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{AstFragment, Invocation, InvocationKind, SupportsMacroExpansion};
-use rustc_feature::is_builtin_attr_name;
 use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, LocalDefId};
-use rustc_hir::PrimTy;
 use rustc_middle::middle::stability;
-use rustc_middle::ty::{self, RegisteredTools};
-use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK};
-use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
+use rustc_middle::ty::RegisteredTools;
+use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
 use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
@@ -35,7 +32,7 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use std::cell::Cell;
-use std::{mem, ptr};
+use std::mem;
 
 type Res = def::Res<NodeId>;
 
@@ -73,10 +70,10 @@ pub enum MacroRulesScope<'a> {
 /// in a module (including derives) and hurt performance.
 pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>;
 
-// Macro namespace is separated into two sub-namespaces, one for bang macros and
-// one for attribute-like macros (attributes, derives).
-// We ignore resolutions from one sub-namespace when searching names in scope for another.
-fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool {
+/// Macro namespace is separated into two sub-namespaces, one for bang macros and
+/// one for attribute-like macros (attributes, derives).
+/// We ignore resolutions from one sub-namespace when searching names in scope for another.
+crate fn sub_namespace_match(candidate: Option<MacroKind>, requirement: Option<MacroKind>) -> bool {
     #[derive(PartialEq)]
     enum SubNS {
         Bang,
@@ -415,7 +412,7 @@ fn cfg_accessible(
 
         let mut indeterminate = false;
         for ns in [TypeNS, ValueNS, MacroNS].iter().copied() {
-            match self.resolve_path(path, Some(ns), &parent_scope, Finalize::No) {
+            match self.maybe_resolve_path(path, Some(ns), &parent_scope) {
                 PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true),
                 PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => {
                     return Ok(true);
@@ -575,7 +572,7 @@ pub fn resolve_macro_path(
         }
 
         let res = if path.len() > 1 {
-            let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, Finalize::No) {
+            let res = match self.maybe_resolve_path(&path, Some(MacroNS), parent_scope) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                     Ok(path_res.base_res())
                 }
@@ -607,6 +604,8 @@ pub fn resolve_macro_path(
                 parent_scope,
                 None,
                 force,
+                false,
+                None,
             );
             if let Err(Determinacy::Undetermined) = binding {
                 return Err(Determinacy::Undetermined);
@@ -630,355 +629,6 @@ pub fn resolve_macro_path(
         res.map(|res| (self.get_macro(res), res))
     }
 
-    // Resolve an identifier in lexical scope.
-    // This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during
-    // expansion and import resolution (perhaps they can be merged in the future).
-    // The function is used for resolving initial segments of macro paths (e.g., `foo` in
-    // `foo::bar!(); or `foo!();`) and also for import paths on 2018 edition.
-    crate fn early_resolve_ident_in_lexical_scope(
-        &mut self,
-        orig_ident: Ident,
-        scope_set: ScopeSet<'a>,
-        parent_scope: &ParentScope<'a>,
-        finalize: Option<Span>,
-        force: bool,
-    ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        bitflags::bitflags! {
-            struct Flags: u8 {
-                const MACRO_RULES          = 1 << 0;
-                const MODULE               = 1 << 1;
-                const MISC_SUGGEST_CRATE   = 1 << 2;
-                const MISC_SUGGEST_SELF    = 1 << 3;
-                const MISC_FROM_PRELUDE    = 1 << 4;
-            }
-        }
-
-        assert!(force || !finalize.is_some()); // `finalize` implies `force`
-
-        // Make sure `self`, `super` etc produce an error when passed to here.
-        if orig_ident.is_path_segment_keyword() {
-            return Err(Determinacy::Determined);
-        }
-
-        let (ns, macro_kind, is_import) = match scope_set {
-            ScopeSet::All(ns, is_import) => (ns, None, is_import),
-            ScopeSet::AbsolutePath(ns) => (ns, None, false),
-            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
-            ScopeSet::Late(ns, ..) => (ns, None, false),
-        };
-
-        // This is *the* result, resolution from the scope closest to the resolved identifier.
-        // However, sometimes this result is "weak" because it comes from a glob import or
-        // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
-        // mod m { ... } // solution in outer scope
-        // {
-        //     use prefix::*; // imports another `m` - innermost solution
-        //                    // weak, cannot shadow the outer `m`, need to report ambiguity error
-        //     m::mac!();
-        // }
-        // So we have to save the innermost solution and continue searching in outer scopes
-        // to detect potential ambiguities.
-        let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
-        let mut determinacy = Determinacy::Determined;
-
-        // Go through all the scopes and try to resolve the name.
-        let break_result = self.visit_scopes(
-            scope_set,
-            parent_scope,
-            orig_ident.span.ctxt(),
-            |this, scope, use_prelude, ctxt| {
-                let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt));
-                let ok = |res, span, arenas| {
-                    Ok((
-                        (res, ty::Visibility::Public, span, LocalExpnId::ROOT)
-                            .to_name_binding(arenas),
-                        Flags::empty(),
-                    ))
-                };
-                let result = match scope {
-                    Scope::DeriveHelpers(expn_id) => {
-                        if let Some(attr) = this
-                            .helper_attrs
-                            .get(&expn_id)
-                            .and_then(|attrs| attrs.iter().rfind(|i| ident == **i))
-                        {
-                            let binding = (
-                                Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
-                                ty::Visibility::Public,
-                                attr.span,
-                                expn_id,
-                            )
-                                .to_name_binding(this.arenas);
-                            Ok((binding, Flags::empty()))
-                        } else {
-                            Err(Determinacy::Determined)
-                        }
-                    }
-                    Scope::DeriveHelpersCompat => {
-                        let mut result = Err(Determinacy::Determined);
-                        for derive in parent_scope.derives {
-                            let parent_scope = &ParentScope { derives: &[], ..*parent_scope };
-                            match this.resolve_macro_path(
-                                derive,
-                                Some(MacroKind::Derive),
-                                parent_scope,
-                                true,
-                                force,
-                            ) {
-                                Ok((Some(ext), _)) => {
-                                    if ext.helper_attrs.contains(&ident.name) {
-                                        result = ok(
-                                            Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat),
-                                            derive.span,
-                                            this.arenas,
-                                        );
-                                        break;
-                                    }
-                                }
-                                Ok(_) | Err(Determinacy::Determined) => {}
-                                Err(Determinacy::Undetermined) => {
-                                    result = Err(Determinacy::Undetermined)
-                                }
-                            }
-                        }
-                        result
-                    }
-                    Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
-                        MacroRulesScope::Binding(macro_rules_binding)
-                            if ident == macro_rules_binding.ident =>
-                        {
-                            Ok((macro_rules_binding.binding, Flags::MACRO_RULES))
-                        }
-                        MacroRulesScope::Invocation(_) => Err(Determinacy::Undetermined),
-                        _ => Err(Determinacy::Determined),
-                    },
-                    Scope::CrateRoot => {
-                        let root_ident = Ident::new(kw::PathRoot, ident.span);
-                        let root_module = this.resolve_crate_root(root_ident);
-                        let binding = this.resolve_ident_in_module_ext(
-                            ModuleOrUniformRoot::Module(root_module),
-                            ident,
-                            ns,
-                            parent_scope,
-                            finalize,
-                        );
-                        match binding {
-                            Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
-                            Err((Determinacy::Undetermined, Weak::No)) => {
-                                return Some(Err(Determinacy::determined(force)));
-                            }
-                            Err((Determinacy::Undetermined, Weak::Yes)) => {
-                                Err(Determinacy::Undetermined)
-                            }
-                            Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
-                        }
-                    }
-                    Scope::Module(module, derive_fallback_lint_id) => {
-                        let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
-                        let binding = this.resolve_ident_in_module_unadjusted_ext(
-                            ModuleOrUniformRoot::Module(module),
-                            ident,
-                            ns,
-                            adjusted_parent_scope,
-                            !matches!(scope_set, ScopeSet::Late(..)),
-                            finalize,
-                        );
-                        match binding {
-                            Ok(binding) => {
-                                if let Some(lint_id) = derive_fallback_lint_id {
-                                    this.lint_buffer.buffer_lint_with_diagnostic(
-                                        PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
-                                        lint_id,
-                                        orig_ident.span,
-                                        &format!(
-                                            "cannot find {} `{}` in this scope",
-                                            ns.descr(),
-                                            ident
-                                        ),
-                                        BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
-                                            orig_ident.span,
-                                        ),
-                                    );
-                                }
-                                let misc_flags = if ptr::eq(module, this.graph_root) {
-                                    Flags::MISC_SUGGEST_CRATE
-                                } else if module.is_normal() {
-                                    Flags::MISC_SUGGEST_SELF
-                                } else {
-                                    Flags::empty()
-                                };
-                                Ok((binding, Flags::MODULE | misc_flags))
-                            }
-                            Err((Determinacy::Undetermined, Weak::No)) => {
-                                return Some(Err(Determinacy::determined(force)));
-                            }
-                            Err((Determinacy::Undetermined, Weak::Yes)) => {
-                                Err(Determinacy::Undetermined)
-                            }
-                            Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
-                        }
-                    }
-                    Scope::RegisteredAttrs => match this.registered_attrs.get(&ident).cloned() {
-                        Some(ident) => ok(
-                            Res::NonMacroAttr(NonMacroAttrKind::Registered),
-                            ident.span,
-                            this.arenas,
-                        ),
-                        None => Err(Determinacy::Determined),
-                    },
-                    Scope::MacroUsePrelude => {
-                        match this.macro_use_prelude.get(&ident.name).cloned() {
-                            Some(binding) => Ok((binding, Flags::MISC_FROM_PRELUDE)),
-                            None => Err(Determinacy::determined(
-                                this.graph_root.unexpanded_invocations.borrow().is_empty(),
-                            )),
-                        }
-                    }
-                    Scope::BuiltinAttrs => {
-                        if is_builtin_attr_name(ident.name) {
-                            ok(
-                                Res::NonMacroAttr(NonMacroAttrKind::Builtin(ident.name)),
-                                DUMMY_SP,
-                                this.arenas,
-                            )
-                        } else {
-                            Err(Determinacy::Determined)
-                        }
-                    }
-                    Scope::ExternPrelude => {
-                        match this.extern_prelude_get(ident, finalize.is_some()) {
-                            Some(binding) => Ok((binding, Flags::empty())),
-                            None => Err(Determinacy::determined(
-                                this.graph_root.unexpanded_invocations.borrow().is_empty(),
-                            )),
-                        }
-                    }
-                    Scope::ToolPrelude => match this.registered_tools.get(&ident).cloned() {
-                        Some(ident) => ok(Res::ToolMod, ident.span, this.arenas),
-                        None => Err(Determinacy::Determined),
-                    },
-                    Scope::StdLibPrelude => {
-                        let mut result = Err(Determinacy::Determined);
-                        if let Some(prelude) = this.prelude {
-                            if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
-                                ModuleOrUniformRoot::Module(prelude),
-                                ident,
-                                ns,
-                                parent_scope,
-                                None,
-                            ) {
-                                if use_prelude || this.is_builtin_macro(binding.res()) {
-                                    result = Ok((binding, Flags::MISC_FROM_PRELUDE));
-                                }
-                            }
-                        }
-                        result
-                    }
-                    Scope::BuiltinTypes => match PrimTy::from_name(ident.name) {
-                        Some(prim_ty) => ok(Res::PrimTy(prim_ty), DUMMY_SP, this.arenas),
-                        None => Err(Determinacy::Determined),
-                    },
-                };
-
-                match result {
-                    Ok((binding, flags))
-                        if sub_namespace_match(binding.macro_kind(), macro_kind) =>
-                    {
-                        if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) {
-                            return Some(Ok(binding));
-                        }
-
-                        if let Some((innermost_binding, innermost_flags)) = innermost_result {
-                            // 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 is_builtin = |res| {
-                                    matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Builtin(..)))
-                                };
-                                let derive_helper =
-                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
-                                let derive_helper_compat =
-                                    Res::NonMacroAttr(NonMacroAttrKind::DeriveHelperCompat);
-
-                                let ambiguity_error_kind = if is_import {
-                                    Some(AmbiguityKind::Import)
-                                } else if is_builtin(innermost_res) || is_builtin(res) {
-                                    Some(AmbiguityKind::BuiltinAttr)
-                                } else if innermost_res == derive_helper_compat
-                                    || res == derive_helper_compat && innermost_res != derive_helper
-                                {
-                                    Some(AmbiguityKind::DeriveHelper)
-                                } else if innermost_flags.contains(Flags::MACRO_RULES)
-                                    && flags.contains(Flags::MODULE)
-                                    && !this.disambiguate_macro_rules_vs_modularized(
-                                        innermost_binding,
-                                        binding,
-                                    )
-                                    || flags.contains(Flags::MACRO_RULES)
-                                        && innermost_flags.contains(Flags::MODULE)
-                                        && !this.disambiguate_macro_rules_vs_modularized(
-                                            binding,
-                                            innermost_binding,
-                                        )
-                                {
-                                    Some(AmbiguityKind::MacroRulesVsModularized)
-                                } else if innermost_binding.is_glob_import() {
-                                    Some(AmbiguityKind::GlobVsOuter)
-                                } else if innermost_binding
-                                    .may_appear_after(parent_scope.expansion, binding)
-                                {
-                                    Some(AmbiguityKind::MoreExpandedVsOuter)
-                                } else {
-                                    None
-                                };
-                                if let Some(kind) = ambiguity_error_kind {
-                                    let misc = |f: Flags| {
-                                        if f.contains(Flags::MISC_SUGGEST_CRATE) {
-                                            AmbiguityErrorMisc::SuggestCrate
-                                        } else if f.contains(Flags::MISC_SUGGEST_SELF) {
-                                            AmbiguityErrorMisc::SuggestSelf
-                                        } else if f.contains(Flags::MISC_FROM_PRELUDE) {
-                                            AmbiguityErrorMisc::FromPrelude
-                                        } else {
-                                            AmbiguityErrorMisc::None
-                                        }
-                                    };
-                                    this.ambiguity_errors.push(AmbiguityError {
-                                        kind,
-                                        ident: orig_ident,
-                                        b1: innermost_binding,
-                                        b2: binding,
-                                        misc1: misc(innermost_flags),
-                                        misc2: misc(flags),
-                                    });
-                                    return Some(Ok(innermost_binding));
-                                }
-                            }
-                        } else {
-                            // Found the first solution.
-                            innermost_result = Some((binding, flags));
-                        }
-                    }
-                    Ok(..) | Err(Determinacy::Determined) => {}
-                    Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined,
-                }
-
-                None
-            },
-        );
-
-        if let Some(break_result) = break_result {
-            return break_result;
-        }
-
-        // The first found solution was the only one, return it.
-        if let Some((binding, _)) = innermost_result {
-            return Ok(binding);
-        }
-
-        Err(Determinacy::determined(determinacy == Determinacy::Determined || force))
-    }
-
     crate fn finalize_macro_resolutions(&mut self) {
         let check_consistency = |this: &mut Self,
                                  path: &[Segment],
@@ -1024,6 +674,7 @@ struct Flags: u8 {
                 Some(MacroNS),
                 &parent_scope,
                 Finalize::SimplePath(ast::CRATE_NODE_ID, path_span),
+                None,
             ) {
                 PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => {
                     let res = path_res.base_res();
@@ -1059,6 +710,8 @@ struct Flags: u8 {
                 &parent_scope,
                 Some(ident.span),
                 true,
+                false,
+                None,
             ) {
                 Ok(binding) => {
                     let initial_res = initial_binding.map(|initial_binding| {
@@ -1100,6 +753,8 @@ struct Flags: u8 {
                 &parent_scope,
                 Some(ident.span),
                 true,
+                false,
+                None,
             );
         }
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9881046..d70f897 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -20,8 +20,8 @@
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
-    fallback_fluent_bundle, fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, FluentBundle, MultiSpan,
+    fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, EmissionGuarantee,
+    ErrorGuaranteed, FluentBundle, MultiSpan,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -1162,6 +1162,7 @@ pub enum DiagnosticOutput {
 pub fn build_session(
     sopts: config::Options,
     local_crate_source_file: Option<PathBuf>,
+    bundle: Option<Lrc<rustc_errors::FluentBundle>>,
     registry: rustc_errors::registry::Registry,
     diagnostics_output: DiagnosticOutput,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -1214,16 +1215,17 @@ pub fn build_session(
         hash_kind,
     ));
 
-    let bundle = fluent_bundle(
-        &sysroot,
-        sopts.debugging_opts.translate_lang.clone(),
-        sopts.debugging_opts.translate_additional_ftl.as_deref(),
-        sopts.debugging_opts.translate_directionality_markers,
-    )
-    .expect("failed to load fluent bundle");
     let fallback_bundle =
-        fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers)
-            .expect("failed to load fallback fluent bundle");
+        match fallback_fluent_bundle(sopts.debugging_opts.translate_directionality_markers) {
+            Ok(bundle) => bundle,
+            Err(e) => {
+                early_error(
+                    sopts.error_format,
+                    &format!("failed to load fallback fluent bundle: {e}"),
+                );
+            }
+        };
+
     let emitter =
         default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle, write_dest);
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 937e0cf..7ebf323 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -117,7 +117,7 @@ fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str)
         // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
         // which will cause us to require that this method always be called with `Span` hashing
         // enabled.
-        HashingControls { hash_spans, node_id_hashing_mode: _ }
+        HashingControls { hash_spans }
             if hash_spans == !ctx.debug_opts_incremental_ignore_spans() => {}
         other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
     }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 6e526bf..b3773d5 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -6,7 +6,6 @@
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
 use rustc_middle::util::common::record_time;
-use rustc_query_system::ich::NodeIdHashingMode;
 
 use tracing::debug;
 
@@ -111,30 +110,28 @@ fn get_symbol_hash<'tcx>(
         // ought to be the same for every reference anyway.
         assert!(!item_type.has_erasable_regions());
         hcx.while_hashing_spans(false, |hcx| {
-            hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                item_type.hash_stable(hcx, &mut hasher);
+            item_type.hash_stable(hcx, &mut hasher);
 
-                // If this is a function, we hash the signature as well.
-                // This is not *strictly* needed, but it may help in some
-                // situations, see the `run-make/a-b-a-linker-guard` test.
-                if let ty::FnDef(..) = item_type.kind() {
-                    item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
-                }
+            // If this is a function, we hash the signature as well.
+            // This is not *strictly* needed, but it may help in some
+            // situations, see the `run-make/a-b-a-linker-guard` test.
+            if let ty::FnDef(..) = item_type.kind() {
+                item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
+            }
 
-                // also include any type parameters (for generic items)
-                substs.hash_stable(hcx, &mut hasher);
+            // also include any type parameters (for generic items)
+            substs.hash_stable(hcx, &mut hasher);
 
-                if let Some(instantiating_crate) = instantiating_crate {
-                    tcx.def_path_hash(instantiating_crate.as_def_id())
-                        .stable_crate_id()
-                        .hash_stable(hcx, &mut hasher);
-                }
+            if let Some(instantiating_crate) = instantiating_crate {
+                tcx.def_path_hash(instantiating_crate.as_def_id())
+                    .stable_crate_id()
+                    .hash_stable(hcx, &mut hasher);
+            }
 
-                // We want to avoid accidental collision between different types of instances.
-                // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
-                // instances without this.
-                discriminant(&instance.def).hash_stable(hcx, &mut hasher);
-            });
+            // We want to avoid accidental collision between different types of instances.
+            // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+            // instances without this.
+            discriminant(&instance.def).hash_stable(hcx, &mut hasher);
         });
     });
 
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 302b8b7..5daa979 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -634,6 +634,7 @@ pub(super) fn thir_abstract_const<'tcx>(
     }
 }
 
+#[instrument(skip(tcx), level = "debug")]
 pub(super) fn try_unify_abstract_consts<'tcx>(
     tcx: TyCtxt<'tcx>,
     (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index e73b9c9..47292b3 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -55,6 +55,7 @@
 pub struct CastCheck<'tcx> {
     expr: &'tcx hir::Expr<'tcx>,
     expr_ty: Ty<'tcx>,
+    expr_span: Span,
     cast_ty: Ty<'tcx>,
     cast_span: Span,
     span: Span,
@@ -207,7 +208,8 @@ pub fn new(
         cast_span: Span,
         span: Span,
     ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
-        let check = CastCheck { expr, expr_ty, cast_ty, cast_span, span };
+        let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
+        let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
 
         // For better error messages, check for some obviously unsized
         // cases now. We do a more thorough check at the end, once
@@ -240,15 +242,15 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     error_span,
                     format!("cannot cast `{}` as `{}`", fcx.ty_to_string(self.expr_ty), cast_ty),
                 );
-                if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.sess().source_map().span_to_snippet(self.expr_span) {
                     err.span_suggestion(
-                        self.expr.span,
+                        self.expr_span,
                         "dereference the expression",
                         format!("*{}", snippet),
                         Applicability::MaybeIncorrect,
                     );
                 } else {
-                    err.span_help(self.expr.span, "dereference the expression with `*`");
+                    err.span_help(self.expr_span, "dereference the expression with `*`");
                 }
                 err.emit();
             }
@@ -315,7 +317,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     struct_span_err!(fcx.tcx.sess, self.span, E0054, "cannot cast as `bool`");
 
                 if self.expr_ty.is_numeric() {
-                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    match fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                         Ok(snippet) => {
                             err.span_suggestion(
                                 self.span,
@@ -440,7 +442,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
-                    err.span_note(self.expr.span, "this reference is immutable");
+                    err.span_note(self.expr_span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
                 } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
@@ -449,7 +451,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                         .tcx
                         .sess
                         .source_map()
-                        .span_to_snippet(self.expr.span)
+                        .span_to_snippet(self.expr_span)
                         .map_or(false, |snip| snip.starts_with('('));
 
                     // Very crude check to see whether the expression must be wrapped
@@ -458,14 +460,14 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                     let needs_parens =
                         !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
 
-                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    let mut suggestion = vec![(self.expr_span.shrink_to_lo(), sugg)];
                     if needs_parens {
                         suggestion[0].1 += "(";
-                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                        suggestion.push((self.expr_span.shrink_to_hi(), ")".to_string()));
                     }
                     if remove_cast {
                         suggestion.push((
-                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            self.expr_span.shrink_to_hi().to(self.cast_span),
                             String::new(),
                         ));
                     }
@@ -481,7 +483,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 ) {
                     let mut label = true;
                     // Check `impl From<self.expr_ty> for self.cast_ty {}` for accurate suggestion:
-                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                    if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                         if let Some(from_trait) = fcx.tcx.get_diagnostic_item(sym::From) {
                             let ty = fcx.resolve_vars_if_possible(self.cast_ty);
                             // Erase regions to avoid panic in `prove_value` when calling
@@ -550,7 +552,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
 
                 if fcx.tcx.sess.is_nightly_build() {
                     err.span_label(
-                        self.expr.span,
+                        self.expr_span,
                         "consider casting this expression to `*const ()`, \
                         then using `core::ptr::from_raw_parts`",
                     );
@@ -651,7 +653,7 @@ fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed
                 }
             }
             _ => {
-                err.span_help(self.expr.span, "consider using a box or reference as appropriate");
+                err.span_help(self.expr_span, "consider using a box or reference as appropriate");
             }
         }
         err.emit()
@@ -685,7 +687,7 @@ fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
 
     #[instrument(skip(fcx), level = "debug")]
     pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
-        self.expr_ty = fcx.structurally_resolved_type(self.expr.span, self.expr_ty);
+        self.expr_ty = fcx.structurally_resolved_type(self.expr_span, self.expr_ty);
         self.cast_ty = fcx.structurally_resolved_type(self.cast_span, self.cast_ty);
 
         debug!("check_cast({}, {:?} as {:?})", self.expr.hir_id, self.expr_ty, self.cast_ty);
@@ -741,7 +743,7 @@ pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> {
                     ty::FnDef(..) => {
                         // Attempt a coercion to a fn pointer type.
                         let f = fcx.normalize_associated_types_in(
-                            self.expr.span,
+                            self.expr_span,
                             self.expr_ty.fn_sig(fcx.tcx),
                         );
                         let res = fcx.try_coerce(
@@ -997,7 +999,7 @@ fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::I
                 ));
 
                 let msg = "use `.addr()` to obtain the address of a pointer";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                     let scalar_cast = match t_c {
                         ty::cast::IntTy::U(ty::UintTy::Usize) => String::new(),
                         _ => format!(" as {}", self.cast_ty),
@@ -1027,13 +1029,12 @@ fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
             self.expr.hir_id,
             self.span,
             |err| {
-
                 let mut err = err.build(&format!(
                     "strict provenance disallows casting integer `{}` to pointer `{}`",
                     self.expr_ty, self.cast_ty
                 ));
                 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
-                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr.span) {
+                if let Ok(snippet) = fcx.tcx.sess.source_map().span_to_snippet(self.expr_span) {
                     err.span_suggestion(
                         self.span,
                         msg,
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index ecc2996..e6560ca 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -1880,9 +1880,15 @@ fn suggest_traits_to_import(
                                 };
                             let sp = hir.span(id);
                             let sp = if let Some(first_bound) = has_bounds {
-                                // `sp` only covers `T`, change it so that it covers
-                                // `T:` when appropriate
                                 sp.until(first_bound.span())
+                            } else if let Some(colon_sp) =
+                                // If the generic param is declared with a colon but without bounds:
+                                // fn foo<T:>(t: T) { ... }
+                                param.colon_span_for_suggestions(
+                                    self.inh.tcx.sess.source_map(),
+                                )
+                            {
+                                sp.to(colon_sp)
                             } else {
                                 sp
                             };
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index b2be70e..f9664a9 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -816,16 +816,69 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
         hir::GenericParamKind::Const { ty: hir_ty, default: _ } => {
             let ty = tcx.type_of(tcx.hir().local_def_id(param.hir_id));
 
-            let err_ty_str;
-            let mut is_ptr = true;
-            let err = if tcx.features().adt_const_params {
-                match ty.peel_refs().kind() {
+            if tcx.features().adt_const_params {
+                let err = match ty.peel_refs().kind() {
                     ty::FnPtr(_) => Some("function pointers"),
                     ty::RawPtr(_) => Some("raw pointers"),
                     _ => None,
+                };
+
+                if let Some(unsupported_type) = err {
+                    tcx.sess.span_err(
+                        hir_ty.span,
+                        &format!(
+                            "using {} as const generic parameters is forbidden",
+                            unsupported_type
+                        ),
+                    );
+                }
+
+                if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
+                    // We use the same error code in both branches, because this is really the same
+                    // issue: we just special-case the message for type parameters to make it
+                    // clearer.
+                    if let ty::Param(_) = ty.peel_refs().kind() {
+                        // Const parameters may not have type parameters as their types,
+                        // because we cannot be sure that the type parameter derives `PartialEq`
+                        // and `Eq` (just implementing them is not enough for `structural_match`).
+                        struct_span_err!(
+                            tcx.sess,
+                            hir_ty.span,
+                            E0741,
+                            "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
+                            used as the type of a const parameter",
+                            ty,
+                        )
+                        .span_label(
+                            hir_ty.span,
+                            format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
+                        )
+                        .note(
+                            "it is not currently possible to use a type parameter as the type of a \
+                            const parameter",
+                        )
+                        .emit();
+                    } else {
+                        struct_span_err!(
+                            tcx.sess,
+                            hir_ty.span,
+                            E0741,
+                            "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
+                            the type of a const parameter",
+                            ty,
+                        )
+                        .span_label(
+                            hir_ty.span,
+                            format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
+                        )
+                        .emit();
+                    }
                 }
             } else {
-                match ty.kind() {
+                let err_ty_str;
+                let mut is_ptr = true;
+
+                let err = match ty.kind() {
                     ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
                     ty::FnPtr(_) => Some("function pointers"),
                     ty::RawPtr(_) => Some("raw pointers"),
@@ -834,74 +887,33 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                         err_ty_str = format!("`{}`", ty);
                         Some(err_ty_str.as_str())
                     }
-                }
-            };
-            if let Some(unsupported_type) = err {
-                if is_ptr {
-                    tcx.sess.span_err(
-                        hir_ty.span,
-                        &format!(
-                            "using {} as const generic parameters is forbidden",
-                            unsupported_type
-                        ),
-                    );
-                } else {
-                    let mut err = tcx.sess.struct_span_err(
-                        hir_ty.span,
-                        &format!(
-                            "{} is forbidden as the type of a const generic parameter",
-                            unsupported_type
-                        ),
-                    );
-                    err.note("the only supported types are integers, `bool` and `char`");
-                    if tcx.sess.is_nightly_build() {
-                        err.help(
+                };
+
+                if let Some(unsupported_type) = err {
+                    if is_ptr {
+                        tcx.sess.span_err(
+                            hir_ty.span,
+                            &format!(
+                                "using {} as const generic parameters is forbidden",
+                                unsupported_type
+                            ),
+                        );
+                    } else {
+                        let mut err = tcx.sess.struct_span_err(
+                            hir_ty.span,
+                            &format!(
+                                "{} is forbidden as the type of a const generic parameter",
+                                unsupported_type
+                            ),
+                        );
+                        err.note("the only supported types are integers, `bool` and `char`");
+                        if tcx.sess.is_nightly_build() {
+                            err.help(
                             "more complex types are supported with `#![feature(adt_const_params)]`",
                         );
+                        }
+                        err.emit();
                     }
-                    err.emit();
-                }
-            };
-
-            if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
-                // We use the same error code in both branches, because this is really the same
-                // issue: we just special-case the message for type parameters to make it
-                // clearer.
-                if let ty::Param(_) = ty.peel_refs().kind() {
-                    // Const parameters may not have type parameters as their types,
-                    // because we cannot be sure that the type parameter derives `PartialEq`
-                    // and `Eq` (just implementing them is not enough for `structural_match`).
-                    struct_span_err!(
-                        tcx.sess,
-                        hir_ty.span,
-                        E0741,
-                        "`{}` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be \
-                            used as the type of a const parameter",
-                        ty,
-                    )
-                    .span_label(
-                        hir_ty.span,
-                        format!("`{}` may not derive both `PartialEq` and `Eq`", ty),
-                    )
-                    .note(
-                        "it is not currently possible to use a type parameter as the type of a \
-                            const parameter",
-                    )
-                    .emit();
-                } else {
-                    struct_span_err!(
-                        tcx.sess,
-                        hir_ty.span,
-                        E0741,
-                        "`{}` must be annotated with `#[derive(PartialEq, Eq)]` to be used as \
-                            the type of a const parameter",
-                        ty,
-                    )
-                    .span_label(
-                        hir_ty.span,
-                        format!("`{}` doesn't derive both `PartialEq` and `Eq`", ty),
-                    )
-                    .emit();
                 }
             }
         }
diff --git a/compiler/rustc_typeck/src/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs
index 4b23cc4..77a53744 100644
--- a/compiler/rustc_typeck/src/coherence/orphan.rs
+++ b/compiler/rustc_typeck/src/coherence/orphan.rs
@@ -7,6 +7,7 @@
 use rustc_hir as hir;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
 use rustc_middle::ty::{self, ImplPolarity, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_session::lint;
@@ -141,13 +142,56 @@ fn orphan_check_impl(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua
         }
     }
 
-    if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() {
-        let reported = tcx
-            .sess
-            .struct_span_err(sp, "cannot implement trait on type alias impl trait")
-            .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
-            .emit();
-        return Err(reported);
+    // Ensure no opaque types are present in this impl header. See issues #76202 and #86411 for examples,
+    // and #84660 where it would otherwise allow unsoundness.
+    if trait_ref.has_opaque_types() {
+        trace!("{:#?}", item);
+        // First we find the opaque type in question.
+        for ty in trait_ref.substs {
+            for ty in ty.walk() {
+                let ty::subst::GenericArgKind::Type(ty) = ty.unpack() else { continue };
+                let ty::Opaque(def_id, _) = *ty.kind() else { continue };
+                trace!(?def_id);
+
+                // Then we search for mentions of the opaque type's type alias in the HIR
+                struct SpanFinder<'tcx> {
+                    sp: Span,
+                    def_id: DefId,
+                    tcx: TyCtxt<'tcx>,
+                }
+                impl<'v, 'tcx> hir::intravisit::Visitor<'v> for SpanFinder<'tcx> {
+                    #[instrument(level = "trace", skip(self, _id))]
+                    fn visit_path(&mut self, path: &'v hir::Path<'v>, _id: hir::HirId) {
+                        // You can't mention an opaque type directly, so we look for type aliases
+                        if let hir::def::Res::Def(hir::def::DefKind::TyAlias, def_id) = path.res {
+                            // And check if that type alias's type contains the opaque type we're looking for
+                            for arg in self.tcx.type_of(def_id).walk() {
+                                if let GenericArgKind::Type(ty) = arg.unpack() {
+                                    if let ty::Opaque(def_id, _) = *ty.kind() {
+                                        if def_id == self.def_id {
+                                            // Finally we update the span to the mention of the type alias
+                                            self.sp = path.span;
+                                            return;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        hir::intravisit::walk_path(self, path)
+                    }
+                }
+
+                let mut visitor = SpanFinder { sp, def_id, tcx };
+                hir::intravisit::walk_item(&mut visitor, item);
+                let reported = tcx
+                    .sess
+                    .struct_span_err(visitor.sp, "cannot implement trait on type alias impl trait")
+                    .span_note(tcx.def_span(def_id), "type alias impl trait defined here")
+                    .emit();
+                return Err(reported);
+            }
+        }
+        span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
     }
 
     Ok(())
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e6faf1d..639e7f2 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -1192,17 +1192,25 @@ fn default() -> Self {
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for Box<[T]> {
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl<T> const Default for Box<[T]> {
     fn default() -> Self {
-        Box::<[T; 0]>::new([])
+        let ptr: Unique<[T]> = Unique::<[T; 0]>::dangling();
+        Box(ptr, Global)
     }
 }
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
-impl Default for Box<str> {
+#[rustc_const_unstable(feature = "const_default_impls", issue = "87864")]
+impl const Default for Box<str> {
     fn default() -> Self {
-        unsafe { from_boxed_utf8_unchecked(Default::default()) }
+        // SAFETY: This is the same as `Unique::cast<U>` but with an unsized `U = str`.
+        let ptr: Unique<str> = unsafe {
+            let bytes: Unique<[u8]> = Unique::<[u8; 0]>::dangling();
+            Unique::new_unchecked(bytes.as_ptr() as *mut str)
+        };
+        Box(ptr, Global)
     }
 }
 
diff --git a/library/alloc/tests/const_fns.rs b/library/alloc/tests/const_fns.rs
index f448b3eb..49b837b 100644
--- a/library/alloc/tests/const_fns.rs
+++ b/library/alloc/tests/const_fns.rs
@@ -6,6 +6,9 @@
 pub const MY_STRING: String = String::new();
 pub const MY_STRING2: String = Default::default();
 
+pub const MY_BOXED_SLICE: Box<[usize]> = Default::default();
+pub const MY_BOXED_STR: Box<str> = Default::default();
+
 use std::collections::{BTreeMap, BTreeSet};
 
 pub const MY_BTREEMAP: BTreeMap<usize, usize> = BTreeMap::new();
@@ -23,6 +26,9 @@ fn test_const() {
     assert_eq!(MY_VEC, MY_VEC2);
     assert_eq!(MY_STRING, MY_STRING2);
 
+    assert_eq!(MY_VEC, *MY_BOXED_SLICE);
+    assert_eq!(MY_STRING, *MY_BOXED_STR);
+
     assert_eq!(MAP_LEN, 0);
     assert_eq!(SET_LEN, 0);
     assert!(MAP_IS_EMPTY && SET_IS_EMPTY);
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 612e366..6ec178b 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -30,7 +30,7 @@ const fn size_align<T>() -> (usize, usize) {
 #[lang = "alloc_layout"]
 pub struct Layout {
     // size of the requested block of memory, measured in bytes.
-    size_: usize,
+    size: usize,
 
     // alignment of the requested block of memory, measured in bytes.
     // we ensure that this is always a power-of-two, because API's
@@ -39,7 +39,7 @@ pub struct Layout {
     //
     // (However, we do not analogously require `align >= sizeof(void*)`,
     //  even though that is *also* a requirement of `posix_memalign`.)
-    align_: ValidAlign,
+    align: ValidAlign,
 }
 
 impl Layout {
@@ -97,7 +97,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutEr
     #[inline]
     pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         // SAFETY: the caller must ensure that `align` is a power of two.
-        Layout { size_: size, align_: unsafe { ValidAlign::new_unchecked(align) } }
+        Layout { size, align: unsafe { ValidAlign::new_unchecked(align) } }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
@@ -106,7 +106,7 @@ pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutEr
     #[must_use]
     #[inline]
     pub const fn size(&self) -> usize {
-        self.size_
+        self.size
     }
 
     /// The minimum byte alignment for a memory block of this layout.
@@ -116,7 +116,7 @@ pub const fn size(&self) -> usize {
                   without modifying the layout"]
     #[inline]
     pub const fn align(&self) -> usize {
-        self.align_.as_nonzero().get()
+        self.align.as_nonzero().get()
     }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index c7a9a81..b30c8a4 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -108,11 +108,11 @@ pub const fn identity<T>(x: T) -> T {
 /// If you need to do a costly conversion it is better to implement [`From`] with type
 /// `&T` or write a custom function.
 ///
-/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in few aspects:
+/// `AsRef` has the same signature as [`Borrow`], but [`Borrow`] is different in a few aspects:
 ///
 /// - Unlike `AsRef`, [`Borrow`] has a blanket impl for any `T`, and can be used to accept either
 ///   a reference or a value.
-/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for borrowed value are
+/// - [`Borrow`] also requires that [`Hash`], [`Eq`] and [`Ord`] for a borrowed value are
 ///   equivalent to those of the owned value. For this reason, if you want to
 ///   borrow only a single field of a struct you can implement `AsRef`, but not [`Borrow`].
 ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 98c9bf5..8b93cd3 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -5,6 +5,7 @@
 use crate::ascii;
 use crate::intrinsics;
 use crate::mem;
+use crate::ops::{Add, Mul, Sub};
 use crate::str::FromStr;
 
 // Used because the `?` operator is not allowed in a const context.
@@ -954,9 +955,10 @@ pub enum FpCategory {
 }
 
 #[doc(hidden)]
-trait FromStrRadixHelper: PartialOrd + Copy {
-    fn min_value() -> Self;
-    fn max_value() -> Self;
+trait FromStrRadixHelper:
+    PartialOrd + Copy + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self>
+{
+    const MIN: Self;
     fn from_u32(u: u32) -> Self;
     fn checked_mul(&self, other: u32) -> Option<Self>;
     fn checked_sub(&self, other: u32) -> Option<Self>;
@@ -976,12 +978,9 @@ fn from_str(src: &str) -> Result<Self, ParseIntError> {
 }
 from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 }
 
-macro_rules! doit {
+macro_rules! impl_helper_for {
     ($($t:ty)*) => ($(impl FromStrRadixHelper for $t {
-        #[inline]
-        fn min_value() -> Self { Self::MIN }
-        #[inline]
-        fn max_value() -> Self { Self::MAX }
+        const MIN: Self = Self::MIN;
         #[inline]
         fn from_u32(u: u32) -> Self { u as Self }
         #[inline]
@@ -998,7 +997,18 @@ fn checked_add(&self, other: u32) -> Option<Self> {
         }
     })*)
 }
-doit! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
+impl_helper_for! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
+
+/// Determines if a string of text of that length of that radix could be guaranteed to be
+/// stored in the given type T.
+/// Note that if the radix is known to the compiler, it is just the check of digits.len that
+/// is done at runtime.
+#[doc(hidden)]
+#[inline(always)]
+#[unstable(issue = "none", feature = "std_internals")]
+pub fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool {
+    radix <= 16 && digits.len() <= mem::size_of::<T>() * 2 - is_signed_ty as usize
+}
 
 fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
     use self::IntErrorKind::*;
@@ -1014,7 +1024,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
         return Err(PIE { kind: Empty });
     }
 
-    let is_signed_ty = T::from_u32(0) > T::min_value();
+    let is_signed_ty = T::from_u32(0) > T::MIN;
 
     // all valid digits are ascii, so we will just iterate over the utf8 bytes
     // and cast them to chars. .to_digit() will safely return None for anything
@@ -1032,38 +1042,56 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, Par
     };
 
     let mut result = T::from_u32(0);
-    if is_positive {
-        // The number is positive
-        for &c in digits {
-            let x = match (c as char).to_digit(radix) {
-                Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
-            };
-            result = match result.checked_mul(radix) {
-                Some(result) => result,
-                None => return Err(PIE { kind: PosOverflow }),
-            };
-            result = match result.checked_add(x) {
-                Some(result) => result,
-                None => return Err(PIE { kind: PosOverflow }),
+
+    if can_not_overflow::<T>(radix, is_signed_ty, digits) {
+        // If the len of the str is short compared to the range of the type
+        // we are parsing into, then we can be certain that an overflow will not occur.
+        // This bound is when `radix.pow(digits.len()) - 1 <= T::MAX` but the condition
+        // above is a faster (conservative) approximation of this.
+        //
+        // Consider radix 16 as it has the highest information density per digit and will thus overflow the earliest:
+        // `u8::MAX` is `ff` - any str of len 2 is guaranteed to not overflow.
+        // `i8::MAX` is `7f` - only a str of len 1 is guaranteed to not overflow.
+        macro_rules! run_unchecked_loop {
+            ($unchecked_additive_op:expr) => {
+                for &c in digits {
+                    result = result * T::from_u32(radix);
+                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
+                    result = $unchecked_additive_op(result, T::from_u32(x));
+                }
             };
         }
+        if is_positive {
+            run_unchecked_loop!(<T as core::ops::Add>::add)
+        } else {
+            run_unchecked_loop!(<T as core::ops::Sub>::sub)
+        };
     } else {
-        // The number is negative
-        for &c in digits {
-            let x = match (c as char).to_digit(radix) {
-                Some(x) => x,
-                None => return Err(PIE { kind: InvalidDigit }),
-            };
-            result = match result.checked_mul(radix) {
-                Some(result) => result,
-                None => return Err(PIE { kind: NegOverflow }),
-            };
-            result = match result.checked_sub(x) {
-                Some(result) => result,
-                None => return Err(PIE { kind: NegOverflow }),
+        macro_rules! run_checked_loop {
+            ($checked_additive_op:ident, $overflow_err:expr) => {
+                for &c in digits {
+                    // When `radix` is passed in as a literal, rather than doing a slow `imul`
+                    // the compiler can use shifts if `radix` can be expressed as a
+                    // sum of powers of 2 (x*10 can be written as x*8 + x*2).
+                    // When the compiler can't use these optimisations,
+                    // the latency of the multiplication can be hidden by issuing it
+                    // before the result is needed to improve performance on
+                    // modern out-of-order CPU as multiplication here is slower
+                    // than the other instructions, we can get the end result faster
+                    // doing multiplication first and let the CPU spends other cycles
+                    // doing other computation and get multiplication result later.
+                    let mul = result.checked_mul(radix);
+                    let x = (c as char).to_digit(radix).ok_or(PIE { kind: InvalidDigit })?;
+                    result = mul.ok_or_else($overflow_err)?;
+                    result = T::$checked_additive_op(&result, x).ok_or_else($overflow_err)?;
+                }
             };
         }
+        if is_positive {
+            run_checked_loop!(checked_add, || PIE { kind: PosOverflow })
+        } else {
+            run_checked_loop!(checked_sub, || PIE { kind: NegOverflow })
+        };
     }
     Ok(result)
 }
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index f9a317f..181717f 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -3,68 +3,88 @@
 use crate::cmp::Ordering::*;
 use crate::cmp::*;
 
-// macro for implementing n-ary tuple functions and operations
+// Recursive macro for implementing n-ary tuple functions and operations
+//
+// Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
+// will implement everything for (A, B, C), (A, B) and (A,).
 macro_rules! tuple_impls {
-    ( $( ( $( $T:ident )+ ) )+ ) => {
-        $(
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:PartialEq),+> PartialEq for ($($T,)+) where last_type!($($T,)+): ?Sized {
-                #[inline]
-                fn eq(&self, other: &($($T,)+)) -> bool {
-                    $( ${ignore(T)} self.${index()} == other.${index()} )&&+
-                }
-                #[inline]
-                fn ne(&self, other: &($($T,)+)) -> bool {
-                    $( ${ignore(T)} self.${index()} != other.${index()} )||+
-                }
+    // Stopping criteria (1-ary tuple)
+    ($T:ident) => {
+        tuple_impls!(@impl $T);
+    };
+    // Running criteria (n-ary tuple, with n >= 2)
+    ($T:ident $( $U:ident )+) => {
+        tuple_impls!($( $U )+);
+        tuple_impls!(@impl $T $( $U )+);
+    };
+    // "Private" internal implementation
+    (@impl $( $T:ident )+) => {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<$($T:PartialEq),+> PartialEq for ($($T,)+)
+        where
+            last_type!($($T,)+): ?Sized
+        {
+            #[inline]
+            fn eq(&self, other: &($($T,)+)) -> bool {
+                $( ${ignore(T)} self.${index()} == other.${index()} )&&+
             }
-
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Eq),+> Eq for ($($T,)+) where last_type!($($T,)+): ?Sized {}
-
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
-            where
-                last_type!($($T,)+): ?Sized
-            {
-                #[inline]
-                fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
-                    lexical_partial_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn lt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(lt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn le(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(le, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn ge(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(ge, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-                #[inline]
-                fn gt(&self, other: &($($T,)+)) -> bool {
-                    lexical_ord!(gt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
+            #[inline]
+            fn ne(&self, other: &($($T,)+)) -> bool {
+                $( ${ignore(T)} self.${index()} != other.${index()} )||+
             }
+        }
 
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Ord),+> Ord for ($($T,)+) where last_type!($($T,)+): ?Sized {
-                #[inline]
-                fn cmp(&self, other: &($($T,)+)) -> Ordering {
-                    lexical_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
-                }
-            }
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<$($T:Eq),+> Eq for ($($T,)+)
+        where
+            last_type!($($T,)+): ?Sized
+        {}
 
-            #[stable(feature = "rust1", since = "1.0.0")]
-            impl<$($T:Default),+> Default for ($($T,)+) {
-                #[inline]
-                fn default() -> ($($T,)+) {
-                    ($({ let x: $T = Default::default(); x},)+)
-                }
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+)
+        where
+            last_type!($($T,)+): ?Sized
+        {
+            #[inline]
+            fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
+                lexical_partial_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
             }
-        )+
+            #[inline]
+            fn lt(&self, other: &($($T,)+)) -> bool {
+                lexical_ord!(lt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+            }
+            #[inline]
+            fn le(&self, other: &($($T,)+)) -> bool {
+                lexical_ord!(le, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+            }
+            #[inline]
+            fn ge(&self, other: &($($T,)+)) -> bool {
+                lexical_ord!(ge, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+            }
+            #[inline]
+            fn gt(&self, other: &($($T,)+)) -> bool {
+                lexical_ord!(gt, $( ${ignore(T)} self.${index()}, other.${index()} ),+)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<$($T:Ord),+> Ord for ($($T,)+)
+        where
+            last_type!($($T,)+): ?Sized
+        {
+            #[inline]
+            fn cmp(&self, other: &($($T,)+)) -> Ordering {
+                lexical_cmp!($( ${ignore(T)} self.${index()}, other.${index()} ),+)
+            }
+        }
+
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl<$($T:Default),+> Default for ($($T,)+) {
+            #[inline]
+            fn default() -> ($($T,)+) {
+                ($({ let x: $T = Default::default(); x},)+)
+            }
+        }
     }
 }
 
@@ -105,17 +125,4 @@ macro_rules! last_type {
     ($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
 }
 
-tuple_impls! {
-    (A)
-    (A B)
-    (A B C)
-    (A B C D)
-    (A B C D E)
-    (A B C D E F)
-    (A B C D E F G)
-    (A B C D E F G H)
-    (A B C D E F G H I)
-    (A B C D E F G H I J)
-    (A B C D E F G H I J K)
-    (A B C D E F G H I J K L)
-}
+tuple_impls!(A B C D E F G H I J K L);
diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs
index 628ac3a..6762c03 100644
--- a/library/core/tests/alloc.rs
+++ b/library/core/tests/alloc.rs
@@ -17,7 +17,7 @@ fn layout_debug_shows_log2_of_alignment() {
     // `Debug` is not stable, but here's what it does right now
     let layout = Layout::from_size_align(24576, 8192).unwrap();
     let s = format!("{:?}", layout);
-    assert_eq!(s, "Layout { size_: 24576, align_: 8192 (1 << 13) }");
+    assert_eq!(s, "Layout { size: 24576, align: 8192 (1 << 13) }");
 }
 
 // Running this normally doesn't do much, but it's also run in Miri, which
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 09e2e04..447a6fc 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -53,6 +53,7 @@
 #![feature(numfmt)]
 #![feature(step_trait)]
 #![feature(str_internals)]
+#![feature(std_internals)]
 #![feature(test)]
 #![feature(trusted_len)]
 #![feature(try_blocks)]
diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs
index 4f773a8..49580cd 100644
--- a/library/core/tests/num/mod.rs
+++ b/library/core/tests/num/mod.rs
@@ -2,7 +2,7 @@
 use core::convert::{TryFrom, TryInto};
 use core::fmt::Debug;
 use core::marker::Copy;
-use core::num::{IntErrorKind, ParseIntError, TryFromIntError};
+use core::num::{can_not_overflow, IntErrorKind, ParseIntError, TryFromIntError};
 use core::ops::{Add, Div, Mul, Rem, Sub};
 use core::option::Option;
 use core::option::Option::None;
@@ -121,6 +121,75 @@ fn test_int_from_str_overflow() {
 }
 
 #[test]
+fn test_can_not_overflow() {
+    fn can_overflow<T>(radix: u32, input: &str) -> bool
+    where
+        T: std::convert::TryFrom<i8>,
+    {
+        !can_not_overflow::<T>(radix, T::try_from(-1_i8).is_ok(), input.as_bytes())
+    }
+
+    // Positive tests:
+    assert!(!can_overflow::<i8>(16, "F"));
+    assert!(!can_overflow::<u8>(16, "FF"));
+
+    assert!(!can_overflow::<i8>(10, "9"));
+    assert!(!can_overflow::<u8>(10, "99"));
+
+    // Negative tests:
+
+    // Not currently in std lib (issue: #27728)
+    fn format_radix<T>(mut x: T, radix: T) -> String
+    where
+        T: std::ops::Rem<Output = T>,
+        T: std::ops::Div<Output = T>,
+        T: std::cmp::PartialEq,
+        T: std::default::Default,
+        T: Copy,
+        T: Default,
+        u32: TryFrom<T>,
+    {
+        let mut result = vec![];
+
+        loop {
+            let m = x % radix;
+            x = x / radix;
+            result.push(
+                std::char::from_digit(m.try_into().ok().unwrap(), radix.try_into().ok().unwrap())
+                    .unwrap(),
+            );
+            if x == T::default() {
+                break;
+            }
+        }
+        result.into_iter().rev().collect()
+    }
+
+    macro_rules! check {
+        ($($t:ty)*) => ($(
+        for base in 2..=36 {
+            let num = (<$t>::MAX as u128) + 1;
+
+           // Calcutate the string length for the smallest overflowing number:
+           let max_len_string = format_radix(num, base as u128);
+           // Ensure that that string length is deemed to potentially overflow:
+           assert!(can_overflow::<$t>(base, &max_len_string));
+        }
+        )*)
+    }
+
+    check! { i8 i16 i32 i64 i128 isize usize u8 u16 u32 u64 }
+
+    // Check u128 separately:
+    for base in 2..=36 {
+        let num = u128::MAX as u128;
+        let max_len_string = format_radix(num, base as u128);
+        // base 16 fits perfectly for u128 and won't overflow:
+        assert_eq!(can_overflow::<u128>(base, &max_len_string), base != 16);
+    }
+}
+
+#[test]
 fn test_leading_plus() {
     test_parse::<u8>("+127", Ok(127));
     test_parse::<i64>("+9223372036854775807", Ok(9223372036854775807));
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 10c4242..433b4d5 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -132,6 +132,16 @@ pub struct File {
 /// An instance of `DirEntry` represents an entry inside of a directory on the
 /// filesystem. Each entry can be inspected via methods to learn about the full
 /// path or possibly other metadata through per-platform extension traits.
+///
+/// # Platform-specific behavior
+///
+/// On Unix, the `DirEntry` struct contains an internal reference to the open
+/// directory. Holding `DirEntry` objects will consume a file handle even
+/// after the `ReadDir` iterator is dropped.
+///
+/// Note that this [may change in the future][changes].
+///
+/// [changes]: io#platform-specific-behavior
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct DirEntry(fs_imp::DirEntry);
 
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 807b057..e6013c7 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -8,7 +8,7 @@
 use crate::fs;
 use crate::marker::PhantomData;
 use crate::mem::forget;
-#[cfg(not(any(target_os = "wasi", target_env = "sgx")))]
+#[cfg(not(any(target_arch = "wasm32", target_env = "sgx")))]
 use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
@@ -76,7 +76,7 @@ pub unsafe fn borrow_raw(fd: RawFd) -> Self {
 impl OwnedFd {
     /// Creates a new `OwnedFd` instance that shares the same underlying file handle
     /// as the existing `OwnedFd` instance.
-    #[cfg(not(target_os = "wasi"))]
+    #[cfg(not(target_arch = "wasm32"))]
     pub fn try_clone(&self) -> crate::io::Result<Self> {
         // We want to atomically duplicate this file descriptor and set the
         // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
@@ -95,7 +95,7 @@ pub fn try_clone(&self) -> crate::io::Result<Self> {
         Ok(unsafe { Self::from_raw_fd(fd) })
     }
 
-    #[cfg(target_os = "wasi")]
+    #[cfg(target_arch = "wasm32")]
     pub fn try_clone(&self) -> crate::io::Result<Self> {
         Err(crate::io::const_io_error!(
             crate::io::ErrorKind::Unsupported,
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index f9c883d..47ee88d 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -5,7 +5,7 @@
 use crate::fs;
 use crate::io;
 use crate::os::raw;
-#[cfg(doc)]
+#[cfg(all(doc, not(target_arch = "wasm32")))]
 use crate::os::unix::io::AsFd;
 #[cfg(unix)]
 use crate::os::unix::io::OwnedFd;
diff --git a/library/std/src/sys/unix/locks/futex.rs b/library/std/src/sys/unix/locks/futex.rs
index 630351d..d97777e 100644
--- a/library/std/src/sys/unix/locks/futex.rs
+++ b/library/std/src/sys/unix/locks/futex.rs
@@ -1,5 +1,6 @@
+use crate::cell::UnsafeCell;
 use crate::sync::atomic::{
-    AtomicI32,
+    AtomicI32, AtomicUsize,
     Ordering::{Acquire, Relaxed, Release},
 };
 use crate::sys::futex::{futex_wait, futex_wake, futex_wake_all};
@@ -162,3 +163,98 @@ unsafe fn wait_optional_timeout(&self, mutex: &Mutex, timeout: Option<Duration>)
         r
     }
 }
+
+/// A reentrant mutex. Used by stdout().lock() and friends.
+///
+/// The 'owner' field tracks which thread has locked the mutex.
+///
+/// We use current_thread_unique_ptr() as the thread identifier,
+/// which is just the address of a thread local variable.
+///
+/// If `owner` is set to the identifier of the current thread,
+/// we assume the mutex is already locked and instead of locking it again,
+/// we increment `lock_count`.
+///
+/// When unlocking, we decrement `lock_count`, and only unlock the mutex when
+/// it reaches zero.
+///
+/// `lock_count` is protected by the mutex and only accessed by the thread that has
+/// locked the mutex, so needs no synchronization.
+///
+/// `owner` can be checked by other threads that want to see if they already
+/// hold the lock, so needs to be atomic. If it compares equal, we're on the
+/// same thread that holds the mutex and memory access can use relaxed ordering
+/// since we're not dealing with multiple threads. If it compares unequal,
+/// synchronization is left to the mutex, making relaxed memory ordering for
+/// the `owner` field fine in all cases.
+pub struct ReentrantMutex {
+    mutex: Mutex,
+    owner: AtomicUsize,
+    lock_count: UnsafeCell<u32>,
+}
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+    #[inline]
+    pub const unsafe fn uninitialized() -> Self {
+        Self { mutex: Mutex::new(), owner: AtomicUsize::new(0), lock_count: UnsafeCell::new(0) }
+    }
+
+    #[inline]
+    pub unsafe fn init(&self) {}
+
+    #[inline]
+    pub unsafe fn destroy(&self) {}
+
+    pub unsafe fn try_lock(&self) -> bool {
+        let this_thread = current_thread_unique_ptr();
+        if self.owner.load(Relaxed) == this_thread {
+            self.increment_lock_count();
+            true
+        } else if self.mutex.try_lock() {
+            self.owner.store(this_thread, Relaxed);
+            debug_assert_eq!(*self.lock_count.get(), 0);
+            *self.lock_count.get() = 1;
+            true
+        } else {
+            false
+        }
+    }
+
+    pub unsafe fn lock(&self) {
+        let this_thread = current_thread_unique_ptr();
+        if self.owner.load(Relaxed) == this_thread {
+            self.increment_lock_count();
+        } else {
+            self.mutex.lock();
+            self.owner.store(this_thread, Relaxed);
+            debug_assert_eq!(*self.lock_count.get(), 0);
+            *self.lock_count.get() = 1;
+        }
+    }
+
+    unsafe fn increment_lock_count(&self) {
+        *self.lock_count.get() = (*self.lock_count.get())
+            .checked_add(1)
+            .expect("lock count overflow in reentrant mutex");
+    }
+
+    pub unsafe fn unlock(&self) {
+        *self.lock_count.get() -= 1;
+        if *self.lock_count.get() == 0 {
+            self.owner.store(0, Relaxed);
+            self.mutex.unlock();
+        }
+    }
+}
+
+/// Get an address that is unique per running thread.
+///
+/// This can be used as a non-null usize-sized ID.
+pub fn current_thread_unique_ptr() -> usize {
+    // Use a non-drop type to make sure it's still available during thread destruction.
+    thread_local! { static X: u8 = const { 0 } }
+    X.with(|x| <*const _>::addr(x))
+}
diff --git a/library/std/src/sys/unix/locks/mod.rs b/library/std/src/sys/unix/locks/mod.rs
index 85afc93..e0404f4 100644
--- a/library/std/src/sys/unix/locks/mod.rs
+++ b/library/std/src/sys/unix/locks/mod.rs
@@ -5,11 +5,7 @@
     ))] {
         mod futex;
         mod futex_rwlock;
-        #[allow(dead_code)]
-        mod pthread_mutex; // Only used for PthreadMutexAttr, needed by pthread_remutex.
-        mod pthread_remutex; // FIXME: Implement this using a futex
-        pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar};
-        pub use pthread_remutex::ReentrantMutex;
+        pub use futex::{Mutex, MovableMutex, Condvar, MovableCondvar, ReentrantMutex};
         pub use futex_rwlock::{RwLock, MovableRwLock};
     } else {
         mod pthread_mutex;
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index e65c11b..3ad03a8 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -215,6 +215,7 @@ pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
     }
 }
 
+#[allow(dead_code)] // Not used on all platforms.
 pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
     if error == 0 { Ok(()) } else { Err(crate::io::Error::from_raw_os_error(error)) }
 }
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index fc307c5..047d07a 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -179,6 +179,7 @@ macro_rules! __thread_local_inner {
     // used to generate the `LocalKey` value for const-initialized thread locals
     (@key $t:ty, const $init:expr) => {{
         #[cfg_attr(not(windows), inline(always))] // see comments below
+        #[deny(unsafe_op_in_unsafe_fn)]
         unsafe fn __getit(
             _init: $crate::option::Option<&mut $crate::option::Option<$t>>,
         ) -> $crate::option::Option<&'static $t> {
@@ -193,7 +194,7 @@ unsafe fn __getit(
             #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))]
             {
                 static mut VAL: $t = INIT_EXPR;
-                $crate::option::Option::Some(&VAL)
+                unsafe { $crate::option::Option::Some(&VAL) }
             }
 
             // If the platform has support for `#[thread_local]`, use it.
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 54b6750..d437397 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -70,7 +70,11 @@
     try:
         if do_verify:
             if url not in checksums:
-                raise RuntimeError("src/stage0.json doesn't contain a checksum for {}".format(url))
+                raise RuntimeError(("src/stage0.json doesn't contain a checksum for {}. "
+                                    "Pre-built artifacts might not available for this "
+                                    "target at this time, see https://doc.rust-lang.org/nightly"
+                                    "/rustc/platform-support.html for more information.")
+                                   .format(url))
             sha256 = checksums[url]
             if os.path.exists(path):
                 if verify(path, sha256, False):
@@ -1173,9 +1177,9 @@
         """Check that vendoring is configured properly"""
         vendor_dir = os.path.join(self.rust_root, 'vendor')
         if 'SUDO_USER' in os.environ and not self.use_vendored_sources:
-            if os.environ.get('USER') != os.environ['SUDO_USER']:
+            if os.getuid() == 0:
                 self.use_vendored_sources = True
-                print('info: looks like you are running this command under `sudo`')
+                print('info: looks like you\'re trying to run this command as root')
                 print('      and so in order to preserve your $HOME this will now')
                 print('      use vendored sources by default.')
                 if not os.path.exists(vendor_dir):
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index e4937d7..59102ad 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -865,8 +865,8 @@ fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf {
                 }
             }
         } else {
-            let base = self.llvm_out(self.config.build).join("build");
-            let base = if !self.ninja() && self.config.build.contains("msvc") {
+            let base = self.llvm_out(target).join("build");
+            let base = if !self.ninja() && target.contains("msvc") {
                 if self.config.llvm_optimize {
                     if self.config.llvm_release_debuginfo {
                         base.join("RelWithDebInfo")
@@ -1176,7 +1176,17 @@ fn qemu_rootfs(&self, target: TargetSelection) -> Option<&Path> {
 
     /// Path to the python interpreter to use
     fn python(&self) -> &Path {
-        self.config.python.as_ref().unwrap()
+        if self.config.build.ends_with("apple-darwin") {
+            // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
+            // LLDB plugin's compiled module which only works with the system python
+            // (namely not Homebrew-installed python)
+            Path::new("/usr/bin/python3")
+        } else {
+            self.config
+                .python
+                .as_ref()
+                .expect("python is required for running LLDB or rustdoc tests")
+        }
     }
 
     /// Temporary directory that extended error information is emitted to.
diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs
index 8c2899c..c96e6f9a 100644
--- a/src/bootstrap/sanity.rs
+++ b/src/bootstrap/sanity.rs
@@ -103,7 +103,9 @@ pub fn check(build: &mut Build) {
         .take()
         .map(|p| cmd_finder.must_have(p))
         .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
-        .or_else(|| Some(cmd_finder.must_have("python")));
+        .or_else(|| cmd_finder.maybe_have("python"))
+        .or_else(|| cmd_finder.maybe_have("python3"))
+        .or_else(|| cmd_finder.maybe_have("python2"));
 
     build.config.nodejs = build
         .config
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index b886847..f60766b 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1402,14 +1402,7 @@ fn run(self, builder: &Builder<'_>) {
 
         cmd.arg("--docck-python").arg(builder.python());
 
-        if builder.config.build.ends_with("apple-darwin") {
-            // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
-            // LLDB plugin's compiled module which only works with the system python
-            // (namely not Homebrew-installed python)
-            cmd.arg("--lldb-python").arg("/usr/bin/python3");
-        } else {
-            cmd.arg("--lldb-python").arg(builder.python());
-        }
+        cmd.arg("--lldb-python").arg(builder.python());
 
         if let Some(ref gdb) = builder.config.gdb {
             cmd.arg("--gdb").arg(gdb);
diff --git a/src/doc/unstable-book/src/compiler-flags/img/llvm-cov-show-01.png b/src/doc/rustc/src/images/llvm-cov-show-01.png
similarity index 100%
rename from src/doc/unstable-book/src/compiler-flags/img/llvm-cov-show-01.png
rename to src/doc/rustc/src/images/llvm-cov-show-01.png
Binary files differ
diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md
index b949891..108b0ff 100644
--- a/src/doc/rustc/src/instrument-coverage.md
+++ b/src/doc/rustc/src/instrument-coverage.md
@@ -145,7 +145,7 @@
     -name=add_quoted_string
 ```
 
-<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
+<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="images/llvm-cov-show-01.png" class="center"/>
 <br/>
 <br/>
 
diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md
index d627f5b..747cc62 100644
--- a/src/doc/rustdoc/src/SUMMARY.md
+++ b/src/doc/rustdoc/src/SUMMARY.md
@@ -9,6 +9,7 @@
     - [Linking to items by name](write-documentation/linking-to-items-by-name.md)
     - [Documentation tests](write-documentation/documentation-tests.md)
 - [Rustdoc-specific lints](lints.md)
+- [Scraped examples](scraped-examples.md)
 - [Advanced features](advanced-features.md)
 - [Unstable features](unstable-features.md)
 - [Deprecated features](deprecated-features.md)
diff --git a/src/doc/rustdoc/src/scraped-examples.md b/src/doc/rustdoc/src/scraped-examples.md
new file mode 100644
index 0000000..d75f6d5
--- /dev/null
+++ b/src/doc/rustdoc/src/scraped-examples.md
@@ -0,0 +1,55 @@
+# Scraped examples
+
+Rustdoc has an unstable feature where it can automatically scrape examples of items being documented from the `examples/` directory of a Cargo workspace. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
+
+```rust,ignore (needs-other-file)
+// a_crate/src/lib.rs
+pub fn a_func() {}
+```
+
+And you have an example calling this function:
+
+```rust,ignore (needs-other-file)
+// a_crate/examples/ex.rs
+fn main() {
+  a_crate::a_func();
+}
+```
+
+Then this code snippet will be included in the documentation for `a_func`. This documentation is inserted by Rustdoc and cannot be manually edited by the crate author.
+
+
+## How to use this feature
+
+This feature is unstable, so you can enable it by calling Rustdoc with the unstable `rustdoc-scrape-examples` flag:
+
+```bash
+cargo doc -Zunstable-options -Zrustdoc-scrape-examples=examples
+```
+
+To enable this feature on [docs.rs](https://docs.rs), add this to your Cargo.toml:
+
+```toml
+[package.metadata.docs.rs]
+cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
+```
+
+
+## How it works
+
+When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items being documented. Then Rustdoc will include the source code of these instances in the generated documentation.
+
+Rustdoc has a few techniques to ensure these examples don't overwhelm documentation readers, and that it doesn't blow up the page size:
+
+1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code.
+2. Only one example is shown by default, and the remaining examples are hidden behind a toggle.
+3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation.
+
+For a given item, Rustdoc sorts its examples based on the size of the example &mdash; smaller ones are shown first.
+
+
+## FAQ
+
+### My example is not showing up in the documentation
+
+This feature uses Cargo's convention for finding examples. You should ensure that `cargo check --examples` includes your example file.
diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh
index a78725f..5f5b48b 100755
--- a/src/etc/pre-push.sh
+++ b/src/etc/pre-push.sh
@@ -1,6 +1,6 @@
 #!/usr/bin/env bash
 #
-# Call `tidy --bless` before each commit
+# Call `tidy --bless` before git push
 # Copy this script to .git/hooks to activate,
 # and remove it from .git/hooks to deactivate.
 #
@@ -14,6 +14,8 @@
 
 if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
   COMMAND="python $COMMAND"
+elif ! command -v python &> /dev/null; then
+  COMMAND="python3 $COMMAND"
 fi
 
 echo "Running pre-push script '$COMMAND'"
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index d06e4fa..33db658 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -79,7 +79,7 @@
         Res::Def(DefKind::TyAlias, did) => {
             record_extern_fqn(cx, did, ItemType::Typedef);
             build_impls(cx, Some(parent_module), did, attrs, &mut ret);
-            clean::TypedefItem(build_type_alias(cx, did), false)
+            clean::TypedefItem(build_type_alias(cx, did))
         }
         Res::Def(DefKind::Enum, did) => {
             record_extern_fqn(cx, did, ItemType::Enum);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 85a3e05..a6763d2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -964,11 +964,11 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let local_did = self.def_id.to_def_id();
         cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
-                hir::TraitItemKind::Const(ref ty, default) => {
-                    let default =
-                        default.map(|e| ConstantKind::Local { def_id: local_did, body: e });
-                    AssocConstItem(ty.clean(cx), default)
-                }
+                hir::TraitItemKind::Const(ref ty, Some(default)) => AssocConstItem(
+                    ty.clean(cx),
+                    ConstantKind::Local { def_id: local_did, body: default },
+                ),
+                hir::TraitItemKind::Const(ref ty, None) => TyAssocConstItem(ty.clean(cx)),
                 hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
                     let m = clean_function(cx, sig, &self.generics, body);
                     MethodItem(m, None)
@@ -983,11 +983,19 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                     });
                     TyMethodItem(Function { decl, generics })
                 }
-                hir::TraitItemKind::Type(bounds, ref default) => {
+                hir::TraitItemKind::Type(bounds, Some(default)) => {
                     let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
                     let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
-                    let default = default.map(|t| t.clean(cx));
-                    AssocTypeItem(Box::new(generics), bounds, default)
+                    let item_type = hir_ty_to_ty(cx.tcx, default).clean(cx);
+                    AssocTypeItem(
+                        Typedef { type_: default.clean(cx), generics, item_type: Some(item_type) },
+                        bounds,
+                    )
+                }
+                hir::TraitItemKind::Type(bounds, None) => {
+                    let generics = enter_impl_trait(cx, |cx| self.generics.clean(cx));
+                    let bounds = bounds.iter().filter_map(|x| x.clean(cx)).collect();
+                    TyAssocTypeItem(Box::new(generics), bounds)
                 }
             };
             let what_rustc_thinks =
@@ -1004,7 +1012,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         cx.with_param_env(local_did, |cx| {
             let inner = match self.kind {
                 hir::ImplItemKind::Const(ref ty, expr) => {
-                    let default = Some(ConstantKind::Local { def_id: local_did, body: expr });
+                    let default = ConstantKind::Local { def_id: local_did, body: expr };
                     AssocConstItem(ty.clean(cx), default)
                 }
                 hir::ImplItemKind::Fn(ref sig, body) => {
@@ -1016,7 +1024,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                     let type_ = hir_ty.clean(cx);
                     let generics = self.generics.clean(cx);
                     let item_type = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
-                    TypedefItem(Typedef { type_, generics, item_type: Some(item_type) }, true)
+                    AssocTypeItem(
+                        Typedef { type_, generics, item_type: Some(item_type) },
+                        Vec::new(),
+                    )
                 }
             };
 
@@ -1041,13 +1052,17 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
         let tcx = cx.tcx;
         let kind = match self.kind {
             ty::AssocKind::Const => {
-                let ty = tcx.type_of(self.def_id);
-                let default = if self.defaultness.has_value() {
-                    Some(ConstantKind::Extern { def_id: self.def_id })
-                } else {
-                    None
+                let ty = tcx.type_of(self.def_id).clean(cx);
+
+                let provided = match self.container {
+                    ty::ImplContainer(_) => true,
+                    ty::TraitContainer(_) => self.defaultness.has_value(),
                 };
-                AssocConstItem(ty.clean(cx), default)
+                if provided {
+                    AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
+                } else {
+                    TyAssocConstItem(ty)
+                }
             }
             ty::AssocKind::Fn => {
                 let generics = clean_ty_generics(
@@ -1181,23 +1196,28 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
                         None => bounds.push(GenericBound::maybe_sized(cx)),
                     }
 
-                    let ty = if self.defaultness.has_value() {
-                        Some(tcx.type_of(self.def_id))
+                    if self.defaultness.has_value() {
+                        AssocTypeItem(
+                            Typedef {
+                                type_: tcx.type_of(self.def_id).clean(cx),
+                                generics,
+                                // FIXME: should we obtain the Type from HIR and pass it on here?
+                                item_type: None,
+                            },
+                            bounds,
+                        )
                     } else {
-                        None
-                    };
-
-                    AssocTypeItem(Box::new(generics), bounds, ty.map(|t| t.clean(cx)))
+                        TyAssocTypeItem(Box::new(generics), bounds)
+                    }
                 } else {
                     // FIXME: when could this happen? Associated items in inherent impls?
-                    let type_ = tcx.type_of(self.def_id).clean(cx);
-                    TypedefItem(
+                    AssocTypeItem(
                         Typedef {
-                            type_,
+                            type_: tcx.type_of(self.def_id).clean(cx),
                             generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
                             item_type: None,
                         },
-                        true,
+                        Vec::new(),
                     )
                 }
             }
@@ -1837,14 +1857,11 @@ fn clean_maybe_renamed_item(
             ItemKind::TyAlias(hir_ty, ref generics) => {
                 let rustdoc_ty = hir_ty.clean(cx);
                 let ty = hir_ty_to_ty(cx.tcx, hir_ty).clean(cx);
-                TypedefItem(
-                    Typedef {
-                        type_: rustdoc_ty,
-                        generics: generics.clean(cx),
-                        item_type: Some(ty),
-                    },
-                    false,
-                )
+                TypedefItem(Typedef {
+                    type_: rustdoc_ty,
+                    generics: generics.clean(cx),
+                    item_type: Some(ty),
+                })
             }
             ItemKind::Enum(ref def, ref generics) => EnumItem(Enum {
                 variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 7698c2d..d2abfc3 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -577,10 +577,16 @@ impl Item {
         self.type_() == ItemType::Variant
     }
     crate fn is_associated_type(&self) -> bool {
-        self.type_() == ItemType::AssocType
+        matches!(&*self.kind, AssocTypeItem(..) | StrippedItem(box AssocTypeItem(..)))
+    }
+    crate fn is_ty_associated_type(&self) -> bool {
+        matches!(&*self.kind, TyAssocTypeItem(..) | StrippedItem(box TyAssocTypeItem(..)))
     }
     crate fn is_associated_const(&self) -> bool {
-        self.type_() == ItemType::AssocConst
+        matches!(&*self.kind, AssocConstItem(..) | StrippedItem(box AssocConstItem(..)))
+    }
+    crate fn is_ty_associated_const(&self) -> bool {
+        matches!(&*self.kind, TyAssocConstItem(..) | StrippedItem(box TyAssocConstItem(..)))
     }
     crate fn is_method(&self) -> bool {
         self.type_() == ItemType::Method
@@ -726,17 +732,18 @@ fn build_fn_header(
     EnumItem(Enum),
     FunctionItem(Function),
     ModuleItem(Module),
-    TypedefItem(Typedef, bool /* is associated type */),
+    TypedefItem(Typedef),
     OpaqueTyItem(OpaqueTy),
     StaticItem(Static),
     ConstantItem(Constant),
     TraitItem(Trait),
     TraitAliasItem(TraitAlias),
     ImplItem(Impl),
-    /// A method signature only. Used for required methods in traits (ie,
-    /// non-default-methods).
+    /// A required method in a trait declaration meaning it's only a function signature.
     TyMethodItem(Function),
-    /// A method with a body.
+    /// A method in a trait impl or a provided method in a trait declaration.
+    ///
+    /// Compared to [TyMethodItem], it also contains a method body.
     MethodItem(Function, Option<hir::Defaultness>),
     StructFieldItem(Type),
     VariantItem(Variant),
@@ -749,12 +756,16 @@ fn build_fn_header(
     MacroItem(Macro),
     ProcMacroItem(ProcMacro),
     PrimitiveItem(PrimitiveType),
-    AssocConstItem(Type, Option<ConstantKind>),
-    /// An associated item in a trait or trait impl.
+    /// A required associated constant in a trait declaration.
+    TyAssocConstItem(Type),
+    /// An associated associated constant in a trait impl or a provided one in a trait declaration.
+    AssocConstItem(Type, ConstantKind),
+    /// A required associated type in a trait declaration.
     ///
     /// The bounds may be non-empty if there is a `where` clause.
-    /// The `Option<Type>` is the default concrete type (e.g. `trait Trait { type Target = usize; }`)
-    AssocTypeItem(Box<Generics>, Vec<GenericBound>, Option<Type>),
+    TyAssocTypeItem(Box<Generics>, Vec<GenericBound>),
+    /// An associated type in a trait impl or a provided one in a trait declaration.
+    AssocTypeItem(Typedef, Vec<GenericBound>),
     /// An item that has been stripped by a rustdoc pass
     StrippedItem(Box<ItemKind>),
     KeywordItem(Symbol),
@@ -776,7 +787,7 @@ impl ItemKind {
             ExternCrateItem { .. }
             | ImportItem(_)
             | FunctionItem(_)
-            | TypedefItem(_, _)
+            | TypedefItem(_)
             | OpaqueTyItem(_)
             | StaticItem(_)
             | ConstantItem(_)
@@ -791,7 +802,9 @@ impl ItemKind {
             | MacroItem(_)
             | ProcMacroItem(_)
             | PrimitiveItem(_)
+            | TyAssocConstItem(_)
             | AssocConstItem(_, _)
+            | TyAssocTypeItem(..)
             | AssocTypeItem(..)
             | StrippedItem(_)
             | KeywordItem(_) => [].iter(),
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c85ef0a..fe6d680 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -178,7 +178,7 @@ pub(super) fn external_path(
 
     for item in items {
         let target = match *item.kind {
-            ItemKind::TypedefItem(ref t, true) => &t.type_,
+            ItemKind::AssocTypeItem(ref t, _) => &t.type_,
             _ => continue,
         };
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 50ae22b..eabe080 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1069,13 +1069,7 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                             }
                         }
                         TestFailure::ExecutionFailure(out) => {
-                            let reason = if let Some(code) = out.status.code() {
-                                format!("exit code {code}")
-                            } else {
-                                String::from("terminated by signal")
-                            };
-
-                            eprintln!("Test executable failed ({reason}).");
+                            eprintln!("Test executable failed ({reason}).", reason = out.status);
 
                             // FIXME(#12309): An unfortunate side-effect of capturing the test
                             // executable's output is that the relative ordering between the test's
diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs
index fbb8b57..95adc44 100644
--- a/src/librustdoc/fold.rs
+++ b/src/librustdoc/fold.rs
@@ -71,7 +71,7 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
-            | TypedefItem(_, _)
+            | TypedefItem(_)
             | OpaqueTyItem(_)
             | StaticItem(_)
             | ConstantItem(_)
@@ -85,7 +85,9 @@ fn fold_inner_recur(&mut self, kind: ItemKind) -> ItemKind {
             | MacroItem(_)
             | ProcMacroItem(_)
             | PrimitiveItem(_)
-            | AssocConstItem(_, _)
+            | TyAssocConstItem(..)
+            | AssocConstItem(..)
+            | TyAssocTypeItem(..)
             | AssocTypeItem(..)
             | KeywordItem(_) => kind,
         }
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index 5315970..663e18f 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -242,14 +242,15 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         if let Some(ref s) = item.name {
             let (parent, is_inherent_impl_item) = match *item.kind {
                 clean::StrippedItem(..) => ((None, None), false),
-                clean::AssocConstItem(..) | clean::TypedefItem(_, true)
+                clean::AssocConstItem(..) | clean::AssocTypeItem(..)
                     if self.cache.parent_is_trait_impl =>
                 {
                     // skip associated items in trait impls
                     ((None, None), false)
                 }
-                clean::AssocTypeItem(..)
-                | clean::TyMethodItem(..)
+                clean::TyMethodItem(..)
+                | clean::TyAssocConstItem(..)
+                | clean::TyAssocTypeItem(..)
                 | clean::StructFieldItem(..)
                 | clean::VariantItem(..) => (
                     (
@@ -258,7 +259,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                     ),
                     false,
                 ),
-                clean::MethodItem(..) | clean::AssocConstItem(..) => {
+                clean::MethodItem(..) | clean::AssocConstItem(..) | clean::AssocTypeItem(..) => {
                     if self.cache.parent_stack.is_empty() {
                         ((None, None), false)
                     } else {
@@ -373,7 +374,9 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
             | clean::TyMethodItem(..)
             | clean::MethodItem(..)
             | clean::StructFieldItem(..)
+            | clean::TyAssocConstItem(..)
             | clean::AssocConstItem(..)
+            | clean::TyAssocTypeItem(..)
             | clean::AssocTypeItem(..)
             | clean::StrippedItem(..)
             | clean::KeywordItem(..) => {
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index f8660c2..fb4afb7 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -14,7 +14,7 @@
 /// The search index uses item types encoded as smaller numbers which equal to
 /// discriminants. JavaScript then is used to decode them into the original value.
 /// Consequently, every change to this type should be synchronized to
-/// the `itemTypes` mapping table in `html/static/main.js`.
+/// the `itemTypes` mapping table in `html/static/js/search.js`.
 ///
 /// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and
 /// module headings. If you are adding to this enum and want to ensure that the sidebar also prints
@@ -89,8 +89,8 @@ fn from(item: &'a clean::Item) -> ItemType {
             clean::ForeignStaticItem(..) => ItemType::Static,     // no ForeignStatic
             clean::MacroItem(..) => ItemType::Macro,
             clean::PrimitiveItem(..) => ItemType::Primitive,
-            clean::AssocConstItem(..) => ItemType::AssocConst,
-            clean::AssocTypeItem(..) => ItemType::AssocType,
+            clean::TyAssocConstItem(..) | clean::AssocConstItem(..) => ItemType::AssocConst,
+            clean::TyAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
             clean::ForeignTypeItem => ItemType::ForeignType,
             clean::KeywordItem(..) => ItemType::Keyword,
             clean::TraitAliasItem(..) => ItemType::TraitAlias,
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 5c59609..55b0028 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -527,6 +527,21 @@ fn print<'a, 'tcx: 'a>(
     /// This item is known to rustdoc, but from a crate that does not have documentation generated.
     ///
     /// This can only happen for non-local items.
+    ///
+    /// # Example
+    ///
+    /// Crate `a` defines a public trait and crate `b` – the target crate that depends on `a` –
+    /// implements it for a local type.
+    /// We document `b` but **not** `a` (we only _build_ the latter – with `rustc`):
+    ///
+    /// ```sh
+    /// rustc a.rs --crate-type=lib
+    /// rustdoc b.rs --crate-type=lib --extern=a=liba.rlib
+    /// ```
+    ///
+    /// Now, the associated items in the trait impl want to link to the corresponding item in the
+    /// trait declaration (see `html::render::assoc_href_attr`) but it's not available since their
+    /// *documentation (was) not built*.
     DocumentationNotBuilt,
     /// This can only happen for non-local items when `--document-private-items` is not passed.
     Private,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 943c521..1ebb41b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1452,8 +1452,10 @@ fn init_id_map() -> FxHashMap<String, usize> {
     map.insert("trait-implementations".to_owned(), 1);
     map.insert("synthetic-implementations".to_owned(), 1);
     map.insert("blanket-implementations".to_owned(), 1);
-    map.insert("associated-types".to_owned(), 1);
-    map.insert("associated-const".to_owned(), 1);
+    map.insert("required-associated-types".to_owned(), 1);
+    map.insert("provided-associated-types".to_owned(), 1);
+    map.insert("provided-associated-consts".to_owned(), 1);
+    map.insert("required-associated-consts".to_owned(), 1);
     map.insert("required-methods".to_owned(), 1);
     map.insert("provided-methods".to_owned(), 1);
     map.insert("implementors".to_owned(), 1);
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index 34784bb..9012365 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -17,8 +17,8 @@
 use super::search_index::build_index;
 use super::write_shared::write_shared;
 use super::{
-    collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
-    BASIC_KEYWORDS,
+    collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
+    LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
 };
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -551,6 +551,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
         let crate_name = self.tcx().crate_name(LOCAL_CRATE);
         let final_file = self.dst.join(crate_name.as_str()).join("all.html");
         let settings_file = self.dst.join("settings.html");
+        let scrape_examples_help_file = self.dst.join("scrape-examples-help.html");
 
         let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
         if !root_path.ends_with('/') {
@@ -606,6 +607,20 @@ fn after_krate(&mut self) -> Result<(), Error> {
             &self.shared.style_files,
         );
         self.shared.fs.write(settings_file, v)?;
+
+        if self.shared.layout.scrape_examples_extension {
+            page.title = "About scraped examples";
+            page.description = "How the scraped examples feature works in Rustdoc";
+            let v = layout::render(
+                &self.shared.layout,
+                &page,
+                "",
+                scrape_examples_help(&*self.shared),
+                &self.shared.style_files,
+            );
+            self.shared.fs.write(scrape_examples_help_file, v)?;
+        }
+
         if let Some(ref redirections) = self.shared.redirections {
             if !redirections.borrow().is_empty() {
                 let redirect_map_path =
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 12da165..a4cc42e 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -75,8 +75,10 @@
 use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine};
 use crate::html::sources;
+use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
 use crate::scrape_examples::{CallData, CallLocation};
 use crate::try_none;
+use crate::DOC_RUST_LANG_ORG_CHANNEL;
 
 /// A pair of name and its optional document.
 crate type NameDoc = (String, Option<String>);
@@ -460,6 +462,34 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S
     ))
 }
 
+fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
+    let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
+    content.push_str(&format!(
+      "## More information\n\n\
+      If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
+      DOC_RUST_LANG_ORG_CHANNEL));
+
+    let mut ids = IdMap::default();
+    format!(
+        "<div class=\"main-heading\">\
+            <h1 class=\"fqn\">\
+                <span class=\"in-band\">About scraped examples</span>\
+            </h1>\
+        </div>\
+        <div>{}</div>",
+        Markdown {
+            content: &content,
+            links: &[],
+            ids: &mut ids,
+            error_codes: shared.codes,
+            edition: shared.edition(),
+            playground: &shared.playground,
+            heading_offset: HeadingOffset::H1
+        }
+        .into_string()
+    )
+}
+
 fn document(
     w: &mut Buffer,
     cx: &Context<'_>,
@@ -521,7 +551,7 @@ fn document_short(
         let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
 
         if s.contains('\n') {
-            let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
+            let link = format!(r#" <a{}>Read more</a>"#, assoc_href_attr(item, link, cx));
 
             if let Some(idx) = summary_html.rfind("</p>") {
                 summary_html.insert_str(idx, &link);
@@ -737,42 +767,82 @@ fn render_impls(
     w.write_str(&rendered_impls.join(""));
 }
 
-fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
-    use crate::formats::item_type::ItemType::*;
+/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
+fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
+    let name = it.name.unwrap();
+    let item_type = it.type_();
 
-    let name = it.name.as_ref().unwrap();
-    let ty = match it.type_() {
-        Typedef | AssocType => AssocType,
-        s => s,
+    let href = match link {
+        AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
+        AssocItemLink::Anchor(None) => Some(format!("#{}.{}", item_type, name)),
+        AssocItemLink::GotoSource(did, provided_methods) => {
+            // We're creating a link from the implementation of an associated item to its
+            // declaration in the trait declaration.
+            let item_type = match item_type {
+                // For historical but not technical reasons, the item type of methods in
+                // trait declarations depends on whether the method is required (`TyMethod`) or
+                // provided (`Method`).
+                ItemType::Method | ItemType::TyMethod => {
+                    if provided_methods.contains(&name) {
+                        ItemType::Method
+                    } else {
+                        ItemType::TyMethod
+                    }
+                }
+                // For associated types and constants, no such distinction exists.
+                item_type => item_type,
+            };
+
+            match href(did.expect_def_id(), cx) {
+                Ok((url, ..)) => Some(format!("{}#{}.{}", url, item_type, name)),
+                // The link is broken since it points to an external crate that wasn't documented.
+                // Do not create any link in such case. This is better than falling back to a
+                // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
+                // (that used to happen in older versions). Indeed, in most cases this dummy would
+                // coincide with the `id`. However, it would not always do so.
+                // In general, this dummy would be incorrect:
+                // If the type with the trait impl also had an inherent impl with an assoc. item of
+                // the *same* name as this impl item, the dummy would link to that one even though
+                // those two items are distinct!
+                // In this scenario, the actual `id` of this impl item would be
+                // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
+                Err(HrefError::DocumentationNotBuilt) => None,
+                Err(_) => Some(format!("#{}.{}", item_type, name)),
+            }
+        }
     };
 
-    let anchor = format!("#{}.{}", ty, name);
-    match link {
-        AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
-        AssocItemLink::Anchor(None) => anchor,
-        AssocItemLink::GotoSource(did, _) => {
-            href(did.expect_def_id(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
-        }
-    }
+    // If there is no `href` for the reason explained above, simply do not render it which is valid:
+    // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
+    href.map(|href| format!(" href=\"{}\"", href)).unwrap_or_default()
 }
 
 fn assoc_const(
     w: &mut Buffer,
     it: &clean::Item,
     ty: &clean::Type,
+    default: Option<&clean::ConstantKind>,
     link: AssocItemLink<'_>,
     extra: &str,
     cx: &Context<'_>,
 ) {
     write!(
         w,
-        "{}{}const <a href=\"{}\" class=\"constant\">{}</a>: {}",
-        extra,
-        it.visibility.print_with_space(it.def_id, cx),
-        naive_assoc_href(it, link, cx),
-        it.name.as_ref().unwrap(),
-        ty.print(cx)
+        "{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
+        extra = extra,
+        vis = it.visibility.print_with_space(it.def_id, cx),
+        href = assoc_href_attr(it, link, cx),
+        name = it.name.as_ref().unwrap(),
+        ty = ty.print(cx),
     );
+    if let Some(default) = default {
+        // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the
+        //        hood which adds noisy underscores and a type suffix to number literals.
+        //        This hurts readability in this context especially when more complex expressions
+        //        are involved and it doesn't add much of value.
+        //        Find a way to print constants here without all that jazz.
+        write!(w, " = {}", default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx())));
+    }
 }
 
 fn assoc_type(
@@ -787,9 +857,9 @@ fn assoc_type(
 ) {
     write!(
         w,
-        "{indent}type <a href=\"{href}\" class=\"associatedtype\">{name}</a>{generics}",
+        "{indent}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
         indent = " ".repeat(indent),
-        href = naive_assoc_href(it, link, cx),
+        href = assoc_href_attr(it, link, cx),
         name = it.name.as_ref().unwrap(),
         generics = generics.print(cx),
     );
@@ -814,22 +884,6 @@ fn assoc_method(
 ) {
     let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item");
     let name = meth.name.as_ref().unwrap();
-    let href = match link {
-        AssocItemLink::Anchor(Some(ref id)) => Some(format!("#{}", id)),
-        AssocItemLink::Anchor(None) => Some(format!("#{}.{}", meth.type_(), name)),
-        AssocItemLink::GotoSource(did, provided_methods) => {
-            // We're creating a link from an impl-item to the corresponding
-            // trait-item and need to map the anchored type accordingly.
-            let ty =
-                if provided_methods.contains(name) { ItemType::Method } else { ItemType::TyMethod };
-
-            match (href(did.expect_def_id(), cx), ty) {
-                (Ok(p), ty) => Some(format!("{}#{}.{}", p.0, ty, name)),
-                (Err(HrefError::DocumentationNotBuilt), ItemType::TyMethod) => None,
-                (Err(_), ty) => Some(format!("#{}.{}", ty, name)),
-            }
-        }
-    };
     let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
     // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
     // this condition.
@@ -843,6 +897,7 @@ fn assoc_method(
     let unsafety = header.unsafety.print_with_space();
     let defaultness = print_default_space(meth.is_default());
     let abi = print_abi_with_space(header.abi).to_string();
+    let href = assoc_href_attr(meth, link, cx);
 
     // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
     let generics_len = format!("{:#}", g.print(cx)).len();
@@ -868,7 +923,7 @@ fn assoc_method(
     w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
     write!(
         w,
-        "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a {href} class=\"fnname\">{name}</a>\
+        "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a{href} class=\"fnname\">{name}</a>\
          {generics}{decl}{notable_traits}{where_clause}",
         indent = indent_str,
         vis = vis,
@@ -877,8 +932,7 @@ fn assoc_method(
         unsafety = unsafety,
         defaultness = defaultness,
         abi = abi,
-        // links without a href are valid - https://www.w3schools.com/tags/att_a_href.asp
-        href = href.map(|href| format!("href=\"{}\"", href)).unwrap_or_else(|| "".to_string()),
+        href = href,
         name = name,
         generics = g.print(cx),
         decl = d.full_print(header_len, indent, header.asyncness, cx),
@@ -968,23 +1022,43 @@ fn render_assoc_item(
     cx: &Context<'_>,
     render_mode: RenderMode,
 ) {
-    match *item.kind {
+    match &*item.kind {
         clean::StrippedItem(..) => {}
-        clean::TyMethodItem(ref m) => {
+        clean::TyMethodItem(m) => {
             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
         }
-        clean::MethodItem(ref m, _) => {
+        clean::MethodItem(m, _) => {
             assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
         }
-        clean::AssocConstItem(ref ty, _) => {
-            assoc_const(w, item, ty, link, if parent == ItemType::Trait { "    " } else { "" }, cx)
-        }
-        clean::AssocTypeItem(ref generics, ref bounds, ref default) => assoc_type(
+        kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
+            w,
+            item,
+            ty,
+            match kind {
+                clean::TyAssocConstItem(_) => None,
+                clean::AssocConstItem(_, default) => Some(default),
+                _ => unreachable!(),
+            },
+            link,
+            if parent == ItemType::Trait { "    " } else { "" },
+            cx,
+        ),
+        clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
             w,
             item,
             generics,
             bounds,
-            default.as_ref(),
+            None,
+            link,
+            if parent == ItemType::Trait { 4 } else { 0 },
+            cx,
+        ),
+        clean::AssocTypeItem(ref ty, ref bounds) => assoc_type(
+            w,
+            item,
+            &ty.generics,
+            bounds,
+            Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
             link,
             if parent == ItemType::Trait { 4 } else { 0 },
             cx,
@@ -1205,7 +1279,7 @@ fn render_deref_methods(
         .items
         .iter()
         .find_map(|item| match *item.kind {
-            clean::TypedefItem(ref t, true) => Some(match *t {
+            clean::AssocTypeItem(ref t, _) => Some(match *t {
                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                 _ => (&t.type_, &t.type_),
             }),
@@ -1291,7 +1365,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                             impl_.print(false, cx)
                         );
                         for it in &impl_.items {
-                            if let clean::TypedefItem(ref tydef, _) = *it.kind {
+                            if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
                                 out.push_str("<span class=\"where fmt-newline\">    ");
                                 let empty_set = FxHashSet::default();
                                 let src_link =
@@ -1300,7 +1374,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                                     &mut out,
                                     it,
                                     &tydef.generics,
-                                    &[],
+                                    &[], // intentionally leaving out bounds
                                     Some(&tydef.type_),
                                     src_link,
                                     0,
@@ -1439,7 +1513,7 @@ fn doc_impl_item(
                 if item_type == ItemType::Method { " method-toggle" } else { "" };
             write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
         }
-        match *item.kind {
+        match &*item.kind {
             clean::MethodItem(..) | clean::TyMethodItem(_) => {
                 // Only render when the method is not static or we allow static methods
                 if render_method_item {
@@ -1471,30 +1545,7 @@ fn doc_impl_item(
                     w.write_str("</section>");
                 }
             }
-            clean::TypedefItem(ref tydef, _) => {
-                let source_id = format!("{}.{}", ItemType::AssocType, name);
-                let id = cx.derive_id(source_id.clone());
-                write!(
-                    w,
-                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
-                    id, item_type, in_trait_class
-                );
-                write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-                w.write_str("<h4 class=\"code-header\">");
-                assoc_type(
-                    w,
-                    item,
-                    &tydef.generics,
-                    &[],
-                    Some(&tydef.type_),
-                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
-                    0,
-                    cx,
-                );
-                w.write_str("</h4>");
-                w.write_str("</section>");
-            }
-            clean::AssocConstItem(ref ty, _) => {
+            kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
                 write!(
@@ -1509,6 +1560,11 @@ fn doc_impl_item(
                     w,
                     item,
                     ty,
+                    match kind {
+                        clean::TyAssocConstItem(_) => None,
+                        clean::AssocConstItem(_, default) => Some(default),
+                        _ => unreachable!(),
+                    },
                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
                     "",
                     cx,
@@ -1516,10 +1572,10 @@ fn doc_impl_item(
                 w.write_str("</h4>");
                 w.write_str("</section>");
             }
-            clean::AssocTypeItem(ref generics, ref bounds, ref default) => {
+            clean::TyAssocTypeItem(generics, bounds) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1527,7 +1583,30 @@ fn doc_impl_item(
                     item,
                     generics,
                     bounds,
-                    default.as_ref(),
+                    None,
+                    link.anchor(if trait_.is_some() { &source_id } else { &id }),
+                    0,
+                    cx,
+                );
+                w.write_str("</h4>");
+                w.write_str("</section>");
+            }
+            clean::AssocTypeItem(tydef, _bounds) => {
+                let source_id = format!("{}.{}", item_type, name);
+                let id = cx.derive_id(source_id.clone());
+                write!(
+                    w,
+                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
+                    id, item_type, in_trait_class
+                );
+                write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                w.write_str("<h4 class=\"code-header\">");
+                assoc_type(
+                    w,
+                    item,
+                    &tydef.generics,
+                    &[], // intentionally leaving out bounds
+                    Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
                     0,
                     cx,
@@ -1748,13 +1827,13 @@ pub(crate) fn render_impl_summary(
         write!(w, "{}", i.inner_impl().print(use_absolute, cx));
         if show_def_docs {
             for it in &i.inner_impl().items {
-                if let clean::TypedefItem(ref tydef, _) = *it.kind {
+                if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
                     w.write_str("<span class=\"where fmt-newline\">  ");
                     assoc_type(
                         w,
                         it,
                         &tydef.generics,
-                        &[],
+                        &[], // intentionally leaving out bounds
                         Some(&tydef.type_),
                         AssocItemLink::Anchor(None),
                         0,
@@ -1822,7 +1901,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
         clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
         clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
-        clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
+        clean::TypedefItem(_) => sidebar_typedef(cx, buffer, it),
         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
         _ => {}
@@ -1917,7 +1996,7 @@ fn get_methods(
                 if !for_deref || should_render_item(item, deref_mut, tcx) {
                     Some(SidebarLink {
                         name,
-                        url: get_next_url(used_links, format!("method.{}", name)),
+                        url: get_next_url(used_links, format!("{}.{}", ItemType::Method, name)),
                     })
                 } else {
                     None
@@ -1937,7 +2016,7 @@ fn get_associated_constants(
         .filter_map(|item| match item.name {
             Some(name) if !name.is_empty() && item.is_associated_const() => Some(SidebarLink {
                 name,
-                url: get_next_url(used_links, format!("associatedconstant.{}", name)),
+                url: get_next_url(used_links, format!("{}.{}", ItemType::AssocConst, name)),
             }),
             _ => None,
         })
@@ -2106,7 +2185,7 @@ fn sidebar_deref_methods(
     debug!("found Deref: {:?}", impl_);
     if let Some((target, real_target)) =
         impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
-            clean::TypedefItem(ref t, true) => Some(match *t {
+            clean::AssocTypeItem(ref t, _) => Some(match *t {
                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
                 _ => (&t.type_, &t.type_),
             }),
@@ -2281,19 +2360,37 @@ fn print_sidebar_section(
     print_sidebar_section(
         buf,
         &t.items,
-        "associated-types",
-        "Associated Types",
-        |m| m.is_associated_type(),
-        |sym| format!("<a href=\"#associatedtype.{0}\">{0}</a>", sym),
+        "required-associated-types",
+        "Required Associated Types",
+        |m| m.is_ty_associated_type(),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "associated-const",
-        "Associated Constants",
+        "provided-associated-types",
+        "Provided Associated Types",
+        |m| m.is_associated_type(),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocType),
+    );
+
+    print_sidebar_section(
+        buf,
+        &t.items,
+        "required-associated-consts",
+        "Required Associated Constants",
+        |m| m.is_ty_associated_const(),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
+    );
+
+    print_sidebar_section(
+        buf,
+        &t.items,
+        "provided-associated-consts",
+        "Provided Associated Constants",
         |m| m.is_associated_const(),
-        |sym| format!("<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::AssocConst),
     );
 
     print_sidebar_section(
@@ -2302,7 +2399,7 @@ fn print_sidebar_section(
         "required-methods",
         "Required Methods",
         |m| m.is_ty_method(),
-        |sym| format!("<a href=\"#tymethod.{0}\">{0}</a>", sym),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::TyMethod),
     );
 
     print_sidebar_section(
@@ -2311,7 +2408,7 @@ fn print_sidebar_section(
         "provided-methods",
         "Provided Methods",
         |m| m.is_method(),
-        |sym| format!("<a href=\"#method.{0}\">{0}</a>", sym),
+        |sym| format!("<a href=\"#{1}.{0}\">{0}</a>", sym, ItemType::Method),
     );
 
     let cache = cx.cache();
@@ -2676,7 +2773,9 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
           <span></span>\
           <h5 id=\"{id}\">\
              <a href=\"#{id}\">Examples found in repository</a>\
+             <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
           </h5>",
+        root_path = cx.root_path(),
         id = id
     );
 
@@ -2728,9 +2827,10 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
             .locations
             .iter()
             .map(|loc| {
-                let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+                let (byte_lo, byte_hi) = loc.call_ident.byte_span;
                 let (line_lo, line_hi) = loc.call_expr.line_span;
                 let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
+
                 let line_range = (line_lo - line_min, line_hi - line_min);
                 let (line_url, line_title) = link_to_loc(call_data, loc);
 
@@ -2846,6 +2946,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
                   <summary class=\"hideme\">\
                      <span>More examples</span>\
                   </summary>\
+                  <div class=\"hide-more\">Hide additional examples</div>\
                   <div class=\"more-scraped-examples\">\
                     <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
                     <div class=\"more-scraped-examples-inner\">"
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 99d7475..1ed5c66 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -141,7 +141,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
 
     item_vars.render_into(buf).unwrap();
 
-    match *item.kind {
+    match &*item.kind {
         clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items),
         clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => {
             item_function(buf, cx, item, f)
@@ -150,7 +150,7 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer,
         clean::StructItem(ref s) => item_struct(buf, cx, item, s),
         clean::UnionItem(ref s) => item_union(buf, cx, item, s),
         clean::EnumItem(ref e) => item_enum(buf, cx, item, e),
-        clean::TypedefItem(ref t, is_associated) => item_typedef(buf, cx, item, t, is_associated),
+        clean::TypedefItem(ref t) => item_typedef(buf, cx, item, t),
         clean::MacroItem(ref m) => item_macro(buf, cx, item, m),
         clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m),
         clean::PrimitiveItem(_) => item_primitive(buf, cx, item),
@@ -507,13 +507,15 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
 
 fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
     let bounds = bounds(&t.bounds, false, cx);
-    let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
-    let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
-    let required = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
-    let provided = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
-    let count_types = types.len();
-    let count_consts = consts.len();
-    let count_methods = required.len() + provided.len();
+    let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>();
+    let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
+    let required_consts = t.items.iter().filter(|m| m.is_ty_associated_const()).collect::<Vec<_>>();
+    let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>();
+    let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::<Vec<_>>();
+    let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::<Vec<_>>();
+    let count_types = required_types.len() + provided_types.len();
+    let count_consts = required_consts.len() + provided_consts.len();
+    let count_methods = required_methods.len() + provided_methods.len();
 
     // Output the trait definition
     wrap_into_docblock(w, |w| {
@@ -554,16 +556,18 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                         ),
                     );
                 }
-                for t in &types {
-                    render_assoc_item(
-                        w,
-                        t,
-                        AssocItemLink::Anchor(None),
-                        ItemType::Trait,
-                        cx,
-                        RenderMode::Normal,
-                    );
-                    w.write_str(";\n");
+                for types in [&required_types, &provided_types] {
+                    for t in types {
+                        render_assoc_item(
+                            w,
+                            t,
+                            AssocItemLink::Anchor(None),
+                            ItemType::Trait,
+                            cx,
+                            RenderMode::Normal,
+                        );
+                        w.write_str(";\n");
+                    }
                 }
                 // If there are too many associated constants, hide everything after them
                 // We also do this if the types + consts is large because otherwise we could
@@ -582,28 +586,30 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                         ),
                     );
                 }
-                if !types.is_empty() && !consts.is_empty() {
+                if count_types != 0 && (count_consts != 0 || count_methods != 0) {
                     w.write_str("\n");
                 }
-                for t in &consts {
-                    render_assoc_item(
-                        w,
-                        t,
-                        AssocItemLink::Anchor(None),
-                        ItemType::Trait,
-                        cx,
-                        RenderMode::Normal,
-                    );
-                    w.write_str(";\n");
+                for consts in [&required_consts, &provided_consts] {
+                    for c in consts {
+                        render_assoc_item(
+                            w,
+                            c,
+                            AssocItemLink::Anchor(None),
+                            ItemType::Trait,
+                            cx,
+                            RenderMode::Normal,
+                        );
+                        w.write_str(";\n");
+                    }
                 }
                 if !toggle && should_hide_fields(count_methods) {
                     toggle = true;
                     toggle_open(w, format_args!("{} methods", count_methods));
                 }
-                if !consts.is_empty() && !required.is_empty() {
+                if count_consts != 0 && count_methods != 0 {
                     w.write_str("\n");
                 }
-                for (pos, m) in required.iter().enumerate() {
+                for (pos, m) in required_methods.iter().enumerate() {
                     render_assoc_item(
                         w,
                         m,
@@ -614,14 +620,14 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                     );
                     w.write_str(";\n");
 
-                    if pos < required.len() - 1 {
+                    if pos < required_methods.len() - 1 {
                         w.write_str("<span class=\"item-spacer\"></span>");
                     }
                 }
-                if !required.is_empty() && !provided.is_empty() {
+                if !required_methods.is_empty() && !provided_methods.is_empty() {
                     w.write_str("\n");
                 }
-                for (pos, m) in provided.iter().enumerate() {
+                for (pos, m) in provided_methods.iter().enumerate() {
                     render_assoc_item(
                         w,
                         m,
@@ -640,7 +646,8 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                             w.write_str(" { ... }\n");
                         }
                     }
-                    if pos < provided.len() - 1 {
+
+                    if pos < provided_methods.len() - 1 {
                         w.write_str("<span class=\"item-spacer\"></span>");
                     }
                 }
@@ -703,53 +710,77 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         }
     }
 
-    if !types.is_empty() {
+    if !required_types.is_empty() {
         write_small_section_header(
             w,
-            "associated-types",
-            "Associated Types",
+            "required-associated-types",
+            "Required Associated Types",
             "<div class=\"methods\">",
         );
-        for t in types {
+        for t in required_types {
+            trait_item(w, cx, t, it);
+        }
+        w.write_str("</div>");
+    }
+    if !provided_types.is_empty() {
+        write_small_section_header(
+            w,
+            "provided-associated-types",
+            "Provided Associated Types",
+            "<div class=\"methods\">",
+        );
+        for t in provided_types {
             trait_item(w, cx, t, it);
         }
         w.write_str("</div>");
     }
 
-    if !consts.is_empty() {
+    if !required_consts.is_empty() {
         write_small_section_header(
             w,
-            "associated-const",
-            "Associated Constants",
+            "required-associated-consts",
+            "Required Associated Constants",
             "<div class=\"methods\">",
         );
-        for t in consts {
+        for t in required_consts {
+            trait_item(w, cx, t, it);
+        }
+        w.write_str("</div>");
+    }
+    if !provided_consts.is_empty() {
+        write_small_section_header(
+            w,
+            "provided-associated-consts",
+            "Provided Associated Constants",
+            "<div class=\"methods\">",
+        );
+        for t in provided_consts {
             trait_item(w, cx, t, it);
         }
         w.write_str("</div>");
     }
 
     // Output the documentation for each function individually
-    if !required.is_empty() {
+    if !required_methods.is_empty() {
         write_small_section_header(
             w,
             "required-methods",
-            "Required methods",
+            "Required Methods",
             "<div class=\"methods\">",
         );
-        for m in required {
+        for m in required_methods {
             trait_item(w, cx, m, it);
         }
         w.write_str("</div>");
     }
-    if !provided.is_empty() {
+    if !provided_methods.is_empty() {
         write_small_section_header(
             w,
             "provided-methods",
-            "Provided methods",
+            "Provided Methods",
             "<div class=\"methods\">",
         );
-        for m in provided {
+        for m in provided_methods {
             trait_item(w, cx, m, it);
         }
         w.write_str("</div>");
@@ -933,25 +964,11 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
     render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
 }
 
-fn item_typedef(
-    w: &mut Buffer,
-    cx: &Context<'_>,
-    it: &clean::Item,
-    t: &clean::Typedef,
-    is_associated: bool,
-) {
-    fn write_content(
-        w: &mut Buffer,
-        cx: &Context<'_>,
-        it: &clean::Item,
-        t: &clean::Typedef,
-        is_associated: bool,
-    ) {
+fn item_typedef(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
+    fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
         wrap_item(w, "typedef", |w| {
             render_attributes_in_pre(w, it, "");
-            if !is_associated {
-                write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
-            }
+            write!(w, "{}", it.visibility.print_with_space(it.def_id, cx));
             write!(
                 w,
                 "type {}{}{where_clause} = {type_};",
@@ -963,14 +980,7 @@ fn write_content(
         });
     }
 
-    // If this is an associated typedef, we don't want to wrap it into a docblock.
-    if is_associated {
-        write_content(w, cx, it, t, is_associated);
-    } else {
-        wrap_into_docblock(w, |w| {
-            write_content(w, cx, it, t, is_associated);
-        });
-    }
+    wrap_into_docblock(w, |w| write_content(w, cx, it, t));
 
     document(w, cx, it, None, HeadingOffset::H2);
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 68c88b551..48cb0a4 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -618,7 +618,7 @@
 	position: relative;
 }
 
-.docblock > :not(.information) {
+.docblock > :not(.information):not(.more-examples-toggle) {
 	max-width: 100%;
 	overflow-x: auto;
 }
@@ -840,8 +840,8 @@
 	content: '§';
 }
 
-.docblock a:not(.srclink):not(.test-arrow):hover,
-.docblock-short a:not(.srclink):not(.test-arrow):hover, .item-info a {
+.docblock a:not(.srclink):not(.test-arrow):not(.scrape-help):hover,
+.docblock-short a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, .item-info a {
 	text-decoration: underline;
 }
 
@@ -2038,21 +2038,45 @@
 
 /* Begin: styles for --scrape-examples feature */
 
+.scraped-example-list .scrape-help {
+	margin-left: 10px;
+	padding: 0 4px;
+	font-weight: normal;
+	font-size: 12px;
+	position: relative;
+	bottom: 1px;
+	background: transparent;
+	border-width: 1px;
+	border-style: solid;
+	border-radius: 50px;
+}
+
 .scraped-example-title {
 	font-family: 'Fira Sans';
 }
 
-.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
-	overflow: hidden;
+.scraped-example .code-wrapper {
+	position: relative;
+	display: flex;
+	flex-direction: row;
+	flex-wrap: wrap;
+	width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
 	max-height: 240px;
 }
 
-.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+.scraped-example:not(.expanded) .code-wrapper pre {
 	overflow-y: hidden;
 	max-height: 240px;
 	padding-bottom: 0;
 }
 
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+	overflow-x: hidden;
+}
+
 .scraped-example .code-wrapper .prev {
 	position: absolute;
 	top: 0.25em;
@@ -2077,14 +2101,6 @@
 	cursor: pointer;
 }
 
-.scraped-example .code-wrapper {
-	position: relative;
-	display: flex;
-	flex-direction: row;
-	flex-wrap: wrap;
-	width: 100%;
-}
-
 .scraped-example:not(.expanded) .code-wrapper:before {
 	content: " ";
 	width: 100%;
@@ -2092,7 +2108,6 @@
 	position: absolute;
 	z-index: 100;
 	top: 0;
-	background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
 }
 
 .scraped-example:not(.expanded) .code-wrapper:after {
@@ -2102,12 +2117,6 @@
 	position: absolute;
 	z-index: 100;
 	bottom: 0;
-	background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
-}
-
-.scraped-example:not(.expanded) .code-wrapper {
-	overflow: hidden;
-	max-height: 240px;
 }
 
 .scraped-example .code-wrapper .line-numbers {
@@ -2126,34 +2135,37 @@
 	margin-bottom: 0;
 }
 
+.scraped-example:not(.expanded) .code-wrapper .example-wrap {
+	overflow-x: hidden;
+}
+
 .scraped-example .code-wrapper .example-wrap pre.rust {
 	overflow-x: inherit;
 	width: inherit;
 	overflow-y: hidden;
 }
 
-.scraped-example .example-wrap .rust span.highlight {
-	background: #fcffd6;
-}
-
-.scraped-example .example-wrap .rust span.highlight.focus {
-	background: #f6fdb0;
-}
 
 .more-examples-toggle {
+	max-width: calc(100% + 25px);
 	margin-top: 10px;
+	margin-left: -25px;
 }
 
-.more-examples-toggle summary {
-	color: #999;
+.more-examples-toggle .hide-more {
+	margin-left: 25px;
+	margin-bottom: 5px;
+	cursor: pointer;
+}
+
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
 	font-family: 'Fira Sans';
 }
 
 .more-scraped-examples {
-	margin-left: 25px;
+	margin-left: 5px;
 	display: flex;
 	flex-direction: row;
-	width: calc(100% - 25px);
 }
 
 .more-scraped-examples-inner {
@@ -2169,13 +2181,8 @@
 	cursor: pointer;
 }
 
-.toggle-line:hover .toggle-line-inner {
-	background: #aaa;
-}
-
 .toggle-line-inner {
 	min-width: 2px;
-	background: #ddd;
 	height: 100%;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index e402b35..b1bf06c 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -611,6 +611,18 @@
 	background-color: #ffb454 !important;
 }
 
+
+.scraped-example-list .scrape-help {
+	border-color: #aaa;
+	color: #eee;
+}
+.scraped-example-list .scrape-help:hover {
+	border-color: white;
+	color: white;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+	color: #999;
+}
 .scraped-example .example-wrap .rust span.highlight {
 	background: rgb(91, 59, 1);
 }
@@ -624,8 +636,8 @@
 	background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
 }
 .toggle-line-inner {
-	background: #616161;
+	background: #999;
 }
 .toggle-line:hover .toggle-line-inner {
-	background: #898989;
+	background: #c5c5c5;
 }
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 0a56055..236304c 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -478,6 +478,17 @@
 	border-bottom-color: #ddd;
 }
 
+.scraped-example-list .scrape-help {
+	border-color: #aaa;
+	color: #eee;
+}
+.scraped-example-list .scrape-help:hover {
+	border-color: white;
+	color: white;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+	color: #999;
+}
 .scraped-example .example-wrap .rust span.highlight {
 	background: rgb(91, 59, 1);
 }
@@ -491,8 +502,8 @@
 	background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
 }
 .toggle-line-inner {
-	background: #616161;
+	background: #999;
 }
 .toggle-line:hover .toggle-line-inner {
-	background: #898989;
+	background: #c5c5c5;
 }
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index dc1715b..c923902 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -462,3 +462,33 @@
 .setting-line > .title {
 	border-bottom-color: #D5D5D5;
 }
+
+.scraped-example-list .scrape-help {
+	border-color: #555;
+	color: #333;
+}
+.scraped-example-list .scrape-help:hover {
+	border-color: black;
+	color: black;
+}
+.more-examples-toggle summary, .more-examples-toggle .hide-more {
+	color: #999;
+}
+.scraped-example .example-wrap .rust span.highlight {
+	background: #fcffd6;
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+	background: #f6fdb0;
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+	background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+	background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+.toggle-line-inner {
+	background: #ccc;
+}
+.toggle-line:hover .toggle-line-inner {
+	background: #999;
+}
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index 664b187..a28fb46 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -1,14 +1,28 @@
 /* global addClass, hasClass, removeClass, onEach */
 
 (function () {
-    // Scroll code block to put the given code location in the middle of the viewer
+    // Number of lines shown when code viewer is not expanded
+    const MAX_LINES = 10;
+
+    // Scroll code block to the given code location
     function scrollToLoc(elt, loc) {
-        var wrapper = elt.querySelector(".code-wrapper");
-        var halfHeight = wrapper.offsetHeight / 2;
         var lines = elt.querySelector('.line-numbers');
-        var offsetMid = (lines.children[loc[0]].offsetTop
-                         + lines.children[loc[1]].offsetTop) / 2;
-        var scrollOffset = offsetMid - halfHeight;
+        var scrollOffset;
+
+        // If the block is greater than the size of the viewer,
+        // then scroll to the top of the block. Otherwise scroll
+        // to the middle of the block.
+        if (loc[1] - loc[0] > MAX_LINES) {
+            var line = Math.max(0, loc[0] - 1);
+            scrollOffset = lines.children[line].offsetTop;
+        } else {
+            var wrapper = elt.querySelector(".code-wrapper");
+            var halfHeight = wrapper.offsetHeight / 2;
+            var offsetMid = (lines.children[loc[0]].offsetTop
+                             + lines.children[loc[1]].offsetTop) / 2;
+            scrollOffset = offsetMid - halfHeight;
+        }
+
         lines.scrollTo(0, scrollOffset);
         elt.querySelector(".rust").scrollTo(0, scrollOffset);
     }
@@ -70,8 +84,10 @@
     onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
         // Allow users to click the left border of the <details> section to close it,
         // since the section can be large and finding the [+] button is annoying.
-        toggle.querySelector('.toggle-line').addEventListener('click', function() {
-            toggle.open = false;
+        toggle.querySelectorAll('.toggle-line, .hide-more').forEach(button => {
+            button.addEventListener('click', function() {
+                toggle.open = false;
+            });
         });
 
         var moreExamples = toggle.querySelectorAll('.scraped-example');
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index b0ce63a..ab52304 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -3,7 +3,7 @@
 
 (function() {
 // This mapping table should match the discriminants of
-// `rustdoc::html::item_type::ItemType` type in Rust.
+// `rustdoc::formats::item_type::ItemType` type in Rust.
 var itemTypes = [
     "mod",
     "externcrate",
diff --git a/src/librustdoc/html/static/scrape-examples-help.md b/src/librustdoc/html/static/scrape-examples-help.md
new file mode 100644
index 0000000..035b2e18
--- /dev/null
+++ b/src/librustdoc/html/static/scrape-examples-help.md
@@ -0,0 +1,34 @@
+Rustdoc will automatically scrape examples of documented items from the `examples/` directory of a project. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
+
+```rust
+// src/lib.rs
+pub fn a_func() {}
+```
+
+And you have an example calling this function:
+
+```rust
+// examples/ex.rs
+fn main() {
+  a_crate::a_func();
+}
+```
+
+Then this code snippet will be included in the documentation for `a_func`.
+
+## How to read scraped examples
+
+Scraped examples are shown as blocks of code from a given file. The relevant item will be highlighted. If the file is larger than a couple lines, only a small window will be shown which you can expand by clicking &varr; in the top-right. If a file contains multiple instances of an item, you can use the &pr; and &sc; buttons to toggle through each instance.
+
+If there is more than one file that contains examples, then you should click "More examples" to see these examples.
+
+
+## How Rustdoc scrapes examples
+
+When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items that occur in the crates being documented. Then Rustdoc will include the source code of these instances in the generated documentation.
+
+Rustdoc has a few techniques to ensure this doesn't overwhelm documentation readers, and that it doesn't blow up the page size:
+
+1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code.
+2. Only one example is shown by default, and the remaining examples are hidden behind a toggle.
+3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation.
diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs
index cd369a9..1837e4a 100644
--- a/src/librustdoc/html/static_files.rs
+++ b/src/librustdoc/html/static_files.rs
@@ -39,6 +39,8 @@
 /// --scrape-examples flag that inserts automatically-found examples of usages of items.
 crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
 
+crate static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
+
 /// The file contents of `brush.svg`, the icon used for the theme-switch button.
 crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
 
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index bc63820..a9a6a31 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -219,20 +219,23 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
         StaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignStaticItem(s) => ItemEnum::Static(s.into_tcx(tcx)),
         ForeignTypeItem => ItemEnum::ForeignType,
-        TypedefItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)),
+        TypedefItem(t) => ItemEnum::Typedef(t.into_tcx(tcx)),
         OpaqueTyItem(t) => ItemEnum::OpaqueTy(t.into_tcx(tcx)),
         ConstantItem(c) => ItemEnum::Constant(c.into_tcx(tcx)),
         MacroItem(m) => ItemEnum::Macro(m.source),
         ProcMacroItem(m) => ItemEnum::ProcMacro(m.into_tcx(tcx)),
         PrimitiveItem(p) => ItemEnum::PrimitiveType(p.as_sym().to_string()),
+        TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
         AssocConstItem(ty, default) => {
-            ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: default.map(|c| c.expr(tcx)) }
+            ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
         }
-        AssocTypeItem(g, b, t) => ItemEnum::AssocType {
+        TyAssocTypeItem(g, b) => ItemEnum::AssocType {
             generics: (*g).into_tcx(tcx),
             bounds: b.into_iter().map(|x| x.into_tcx(tcx)).collect(),
-            default: t.map(|x| x.into_tcx(tcx)),
+            default: None,
         },
+        // FIXME: do not map to Typedef but to a custom variant
+        AssocTypeItem(t, _) => ItemEnum::Typedef(t.into_tcx(tcx)),
         // `convert_item` early returns `None` for striped items
         StrippedItem(_) => unreachable!(),
         KeywordItem(_) => {
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index a1f92af..62e42b7 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -1,3 +1,4 @@
+use std::fmt::Write as _;
 use std::fs::{create_dir_all, read_to_string, File};
 use std::io::prelude::*;
 use std::path::Path;
@@ -51,8 +52,8 @@ fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
 
     let mut css = String::new();
     for name in &options.markdown_css {
-        let s = format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{name}\">\n");
-        css.push_str(&s)
+        write!(css, r#"<link rel="stylesheet" type="text/css" href="{name}">"#)
+            .expect("Writing to a String can't fail");
     }
 
     let input_str = read_to_string(input).map_err(|err| format!("{}: {}", input.display(), err))?;
diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs
index 2b17e34..b541fb6 100644
--- a/src/librustdoc/passes/check_doc_test_visibility.rs
+++ b/src/librustdoc/passes/check_doc_test_visibility.rs
@@ -61,9 +61,9 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
             *item.kind,
             clean::StructFieldItem(_)
                 | clean::VariantItem(_)
-                | clean::AssocConstItem(_, _)
+                | clean::AssocConstItem(..)
                 | clean::AssocTypeItem(..)
-                | clean::TypedefItem(_, _)
+                | clean::TypedefItem(_)
                 | clean::StaticItem(_)
                 | clean::ConstantItem(_)
                 | clean::ExternCrateItem { .. }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 2852c3b..4ab942c 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -93,7 +93,7 @@ fn add_deref_target(
                 let target = items
                     .iter()
                     .find_map(|item| match *item.kind {
-                        TypedefItem(ref t, true) => Some(&t.type_),
+                        AssocTypeItem(ref t, _) => Some(&t.type_),
                         _ => None,
                     })
                     .expect("Deref impl without Target type");
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 717dc07..82627aa 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -41,6 +41,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             | clean::ConstantItem(..)
             | clean::UnionItem(..)
             | clean::AssocConstItem(..)
+            | clean::AssocTypeItem(..)
             | clean::TraitAliasItem(..)
             | clean::MacroItem(..)
             | clean::ForeignTypeItem => {
@@ -72,8 +73,8 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
 
             clean::ImplItem(..) => {}
 
-            // tymethods have no control over privacy
-            clean::TyMethodItem(..) => {}
+            // tymethods etc. have no control over privacy
+            clean::TyMethodItem(..) | clean::TyAssocConstItem(..) | clean::TyAssocTypeItem(..) => {}
 
             // Proc-macros are always public
             clean::ProcMacroItem(..) => {}
@@ -81,9 +82,6 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             // Primitives are never stripped
             clean::PrimitiveItem(..) => {}
 
-            // Associated types are never stripped
-            clean::AssocTypeItem(..) => {}
-
             // Keywords are never stripped
             clean::KeywordItem(..) => {}
         }
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 7cf0ea9..0da490f 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -71,33 +71,36 @@ impl ScrapeExamplesOptions {
 }
 
 impl SyntaxRange {
-    fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+    fn new(span: rustc_span::Span, file: &SourceFile) -> Option<Self> {
         let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
-        let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+        let get_line = |bytepos: BytePos| file.lookup_line(bytepos);
 
-        SyntaxRange {
+        Some(SyntaxRange {
             byte_span: (get_pos(span.lo()), get_pos(span.hi())),
-            line_span: (get_line(span.lo()), get_line(span.hi())),
-        }
+            line_span: (get_line(span.lo())?, get_line(span.hi())?),
+        })
     }
 }
 
 #[derive(Encodable, Decodable, Debug, Clone)]
 crate struct CallLocation {
     crate call_expr: SyntaxRange,
+    crate call_ident: SyntaxRange,
     crate enclosing_item: SyntaxRange,
 }
 
 impl CallLocation {
     fn new(
         expr_span: rustc_span::Span,
+        ident_span: rustc_span::Span,
         enclosing_item_span: rustc_span::Span,
         source_file: &SourceFile,
-    ) -> Self {
-        CallLocation {
-            call_expr: SyntaxRange::new(expr_span, source_file),
-            enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
-        }
+    ) -> Option<Self> {
+        Some(CallLocation {
+            call_expr: SyntaxRange::new(expr_span, source_file)?,
+            call_ident: SyntaxRange::new(ident_span, source_file)?,
+            enclosing_item: SyntaxRange::new(enclosing_item_span, source_file)?,
+        })
     }
 }
 
@@ -146,24 +149,26 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         }
 
         // Get type of function if expression is a function call
-        let (ty, span) = match ex.kind {
+        let (ty, call_span, ident_span) = match ex.kind {
             hir::ExprKind::Call(f, _) => {
                 let types = tcx.typeck(ex.hir_id.owner);
 
                 if let Some(ty) = types.node_type_opt(f.hir_id) {
-                    (ty, ex.span)
+                    (ty, ex.span, f.span)
                 } else {
                     trace!("node_type_opt({}) = None", f.hir_id);
                     return;
                 }
             }
-            hir::ExprKind::MethodCall(_, _, span) => {
+            hir::ExprKind::MethodCall(path, _, call_span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
                 let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
                     trace!("type_dependent_def_id({}) = None", ex.hir_id);
                     return;
                 };
-                (tcx.type_of(def_id), span)
+
+                let ident_span = path.ident.span;
+                (tcx.type_of(def_id), call_span, ident_span)
             }
             _ => {
                 return;
@@ -172,8 +177,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
 
         // If this span comes from a macro expansion, then the source code may not actually show
         // a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
-        if span.from_expansion() {
-            trace!("Rejecting expr from macro: {:?}", span);
+        if call_span.from_expansion() {
+            trace!("Rejecting expr from macro: {call_span:?}");
             return;
         }
 
@@ -183,49 +188,82 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
             .hir()
             .span_with_body(tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(ex.hir_id)));
         if enclosing_item_span.from_expansion() {
-            trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
+            trace!("Rejecting expr ({call_span:?}) from macro item: {enclosing_item_span:?}");
             return;
         }
 
-        assert!(
-            enclosing_item_span.contains(span),
-            "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.",
-            span,
-            enclosing_item_span
-        );
+        // If the enclosing item doesn't actually enclose the call, this means we probably have a weird
+        // macro issue even though the spans aren't tagged as being from an expansion.
+        if !enclosing_item_span.contains(call_span) {
+            warn!(
+                "Attempted to scrape call at [{call_span:?}] whose enclosing item [{enclosing_item_span:?}] doesn't contain the span of the call."
+            );
+            return;
+        }
+
+        // Similarly for the call w/ the function ident.
+        if !call_span.contains(ident_span) {
+            warn!(
+                "Attempted to scrape call at [{call_span:?}] whose identifier [{ident_span:?}] was not contained in the span of the call."
+            );
+            return;
+        }
 
         // Save call site if the function resolves to a concrete definition
         if let ty::FnDef(def_id, _) = ty.kind() {
             if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
-                trace!("Rejecting expr from crate not being documented: {:?}", span);
+                trace!("Rejecting expr from crate not being documented: {call_span:?}");
                 return;
             }
 
             let source_map = tcx.sess.source_map();
-            let file = source_map.lookup_char_pos(span.lo()).file;
+            let file = source_map.lookup_char_pos(call_span.lo()).file;
             let file_path = match file.name.clone() {
                 FileName::Real(real_filename) => real_filename.into_local_path(),
                 _ => None,
             };
 
             if let Some(file_path) = file_path {
-                let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+                let abs_path = match fs::canonicalize(file_path.clone()) {
+                    Ok(abs_path) => abs_path,
+                    Err(_) => {
+                        trace!("Could not canonicalize file path: {}", file_path.display());
+                        return;
+                    }
+                };
+
                 let cx = &self.cx;
+                let clean_span = crate::clean::types::Span::new(call_span);
+                let url = match cx.href_from_span(clean_span, false) {
+                    Some(url) => url,
+                    None => {
+                        trace!(
+                            "Rejecting expr ({call_span:?}) whose clean span ({clean_span:?}) cannot be turned into a link"
+                        );
+                        return;
+                    }
+                };
+
                 let mk_call_data = || {
-                    let clean_span = crate::clean::types::Span::new(span);
-                    let url = cx.href_from_span(clean_span, false).unwrap();
                     let display_name = file_path.display().to_string();
-                    let edition = span.edition();
+                    let edition = call_span.edition();
                     CallData { locations: Vec::new(), url, display_name, edition }
                 };
 
                 let fn_key = tcx.def_path_hash(*def_id);
                 let fn_entries = self.calls.entry(fn_key).or_default();
 
-                trace!("Including expr: {:?}", span);
+                trace!("Including expr: {:?}", call_span);
                 let enclosing_item_span =
                     source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false);
-                let location = CallLocation::new(span, enclosing_item_span, &file);
+                let location =
+                    match CallLocation::new(call_span, ident_span, enclosing_item_span, &file) {
+                        Some(location) => location,
+                        None => {
+                            trace!("Could not get serializable call location for {call_span:?}");
+                            return;
+                        }
+                    };
                 fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
             }
         }
@@ -259,8 +297,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
             .map(|(crate_num, _)| **crate_num)
             .collect::<Vec<_>>();
 
-        debug!("All crates in TyCtxt: {:?}", all_crates);
-        debug!("Scrape examples target_crates: {:?}", target_crates);
+        debug!("All crates in TyCtxt: {all_crates:?}");
+        debug!("Scrape examples target_crates: {target_crates:?}");
 
         // Run call-finder on all items
         let mut calls = FxHashMap::default();
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 1e9a65e..7c19865 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -173,15 +173,17 @@ fn build_rule(v: &[u8], positions: &[usize]) -> String {
             .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
             .collect::<String>()
             .trim()
-            .replace('\n', " ")
-            .replace('/', "")
-            .replace('\t', " ")
-            .replace('{', "")
-            .replace('}', "")
+            .chars()
+            .filter_map(|c| match c {
+                '\n' | '\t' => Some(' '),
+                '/' | '{' | '}' => None,
+                c => Some(c),
+            })
+            .collect::<String>()
             .split(' ')
             .filter(|s| !s.is_empty())
-            .collect::<Vec<&str>>()
-            .join(" "),
+            .intersperse(" ")
+            .collect::<String>(),
     )
     .unwrap_or_else(|_| String::new())
 }
diff --git a/src/librustdoc/visit.rs b/src/librustdoc/visit.rs
index b16cab1..ef50292 100644
--- a/src/librustdoc/visit.rs
+++ b/src/librustdoc/visit.rs
@@ -26,7 +26,7 @@ fn visit_inner_recur(&mut self, kind: &ItemKind) {
             ExternCrateItem { src: _ }
             | ImportItem(_)
             | FunctionItem(_)
-            | TypedefItem(_, _)
+            | TypedefItem(_)
             | OpaqueTyItem(_)
             | StaticItem(_)
             | ConstantItem(_)
@@ -40,7 +40,9 @@ fn visit_inner_recur(&mut self, kind: &ItemKind) {
             | MacroItem(_)
             | ProcMacroItem(_)
             | PrimitiveItem(_)
-            | AssocConstItem(_, _)
+            | TyAssocConstItem(..)
+            | AssocConstItem(..)
+            | TyAssocTypeItem(..)
             | AssocTypeItem(..)
             | KeywordItem(_) => {}
         }
diff --git a/src/test/incremental/hashes/if_expressions.rs b/src/test/incremental/hashes/if_expressions.rs
index 0c5e73b..37d67b9 100644
--- a/src/test/incremental/hashes/if_expressions.rs
+++ b/src/test/incremental/hashes/if_expressions.rs
@@ -30,9 +30,9 @@ pub fn change_condition(x: bool) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_condition(x: bool) -> u32 {
     if !x {
@@ -106,9 +106,9 @@ pub fn add_else_branch(x: bool) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_else_branch(x: bool) -> u32 {
     let mut ret = 1;
@@ -159,9 +159,9 @@ pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_then_branch_if_let(x: Option<u32>) -> u32 {
     if let Some(x) = x {
@@ -212,9 +212,9 @@ pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,typeck,optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_else_branch_if_let(x: Option<u32>) -> u32 {
     let mut ret = 1;
diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs
index 0532f4a..12c4d9f 100644
--- a/src/test/incremental/hashes/indexing_expressions.rs
+++ b/src/test/incremental/hashes/indexing_expressions.rs
@@ -77,9 +77,9 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 fn add_lower_bound(slice: &[u32]) -> &[u32] {
     &slice[3..4]
@@ -94,9 +94,9 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 fn add_upper_bound(slice: &[u32]) -> &[u32] {
     &slice[3..7]
@@ -128,9 +128,9 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,typeck", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] {
     &slice[3..=7]
diff --git a/src/test/incremental/hashes/match_expressions.rs b/src/test/incremental/hashes/match_expressions.rs
index 314461b..66a82e8 100644
--- a/src/test/incremental/hashes/match_expressions.rs
+++ b/src/test/incremental/hashes/match_expressions.rs
@@ -31,9 +31,9 @@ pub fn add_arm(x: u32) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_arm(x: u32) -> u32 {
     match x {
@@ -82,9 +82,9 @@ pub fn add_guard_clause(x: u32, y: bool) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -107,9 +107,9 @@ pub fn change_guard_clause(x: u32, y: bool) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_guard_clause(x: u32, y: bool) -> u32 {
     match x {
@@ -132,9 +132,9 @@ pub fn add_at_binding(x: u32) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_at_binding(x: u32) -> u32 {
     match x {
@@ -181,9 +181,9 @@ pub fn change_simple_name_to_pattern(x: u32) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn change_simple_name_to_pattern(x: u32) -> u32 {
     match (x, x & 1) {
@@ -275,9 +275,9 @@ pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_amp_to_binding_in_pattern(x: u32) -> u32 {
     match (&x, x & 1) {
@@ -324,9 +324,9 @@ pub fn add_alternative_to_arm(x: u32) -> u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_alternative_to_arm(x: u32) -> u32 {
     match x {
diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs
index 6a62620..0f29669 100644
--- a/src/test/incremental/hashes/struct_constructors.rs
+++ b/src/test/incremental/hashes/struct_constructors.rs
@@ -93,9 +93,9 @@ pub fn add_field_regular_struct() -> RegularStruct {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,optimized_mir,typeck")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,optimized_mir,typeck")]
 #[rustc_clean(cfg="cfail6")]
 pub fn add_field_regular_struct() -> RegularStruct {
     let struct1 = RegularStruct {
diff --git a/src/test/mir-opt/lower_intrinsics.rs b/src/test/mir-opt/lower_intrinsics.rs
index 8a8880d..eab51b6 100644
--- a/src/test/mir-opt/lower_intrinsics.rs
+++ b/src/test/mir-opt/lower_intrinsics.rs
@@ -3,7 +3,7 @@
 #![crate_type = "lib"]
 
 // EMIT_MIR lower_intrinsics.wrapping.LowerIntrinsics.diff
-pub fn wrapping<T: Copy>(a: T, b: T) {
+pub fn wrapping(a: i32, b: i32) {
     let _x = core::intrinsics::wrapping_add(a, b);
     let _y = core::intrinsics::wrapping_sub(a, b);
     let _z = core::intrinsics::wrapping_mul(a, b);
diff --git a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
index a531a19..5a0286b 100644
--- a/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
+++ b/src/test/mir-opt/lower_intrinsics.wrapping.LowerIntrinsics.diff
@@ -1,23 +1,23 @@
 - // MIR for `wrapping` before LowerIntrinsics
 + // MIR for `wrapping` after LowerIntrinsics
   
-  fn wrapping(_1: T, _2: T) -> () {
-      debug a => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:26: 6:27
-      debug b => _2;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:32: 6:33
-      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:6:38: 6:38
-      let _3: T;                           // in scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11
-      let mut _4: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
-      let mut _5: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
-      let mut _7: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:8:45: 8:46
-      let mut _8: T;                       // in scope 0 at $DIR/lower_intrinsics.rs:8:48: 8:49
-      let mut _10: T;                      // in scope 0 at $DIR/lower_intrinsics.rs:9:45: 9:46
-      let mut _11: T;                      // in scope 0 at $DIR/lower_intrinsics.rs:9:48: 9:49
+  fn wrapping(_1: i32, _2: i32) -> () {
+      debug a => _1;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:17: 6:18
+      debug b => _2;                       // in scope 0 at $DIR/lower_intrinsics.rs:6:25: 6:26
+      let mut _0: ();                      // return place in scope 0 at $DIR/lower_intrinsics.rs:6:33: 6:33
+      let _3: i32;                         // in scope 0 at $DIR/lower_intrinsics.rs:7:9: 7:11
+      let mut _4: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
+      let mut _5: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
+      let mut _7: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:8:45: 8:46
+      let mut _8: i32;                     // in scope 0 at $DIR/lower_intrinsics.rs:8:48: 8:49
+      let mut _10: i32;                    // in scope 0 at $DIR/lower_intrinsics.rs:9:45: 9:46
+      let mut _11: i32;                    // in scope 0 at $DIR/lower_intrinsics.rs:9:48: 9:49
       scope 1 {
           debug _x => _3;                  // in scope 1 at $DIR/lower_intrinsics.rs:7:9: 7:11
-          let _6: T;                       // in scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11
+          let _6: i32;                     // in scope 1 at $DIR/lower_intrinsics.rs:8:9: 8:11
           scope 2 {
               debug _y => _6;              // in scope 2 at $DIR/lower_intrinsics.rs:8:9: 8:11
-              let _9: T;                   // in scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11
+              let _9: i32;                 // in scope 2 at $DIR/lower_intrinsics.rs:9:9: 9:11
               scope 3 {
                   debug _z => _9;          // in scope 3 at $DIR/lower_intrinsics.rs:9:9: 9:11
               }
@@ -30,10 +30,10 @@
           _4 = _1;                         // scope 0 at $DIR/lower_intrinsics.rs:7:45: 7:46
           StorageLive(_5);                 // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
           _5 = _2;                         // scope 0 at $DIR/lower_intrinsics.rs:7:48: 7:49
--         _3 = wrapping_add::<T>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
+-         _3 = wrapping_add::<i32>(move _4, move _5) -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:7:14: 7:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_add::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_add::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _3 = Add(move _4, move _5);      // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
 +         goto -> bb1;                     // scope 0 at $DIR/lower_intrinsics.rs:7:14: 7:50
       }
@@ -46,10 +46,10 @@
           _7 = _1;                         // scope 1 at $DIR/lower_intrinsics.rs:8:45: 8:46
           StorageLive(_8);                 // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49
           _8 = _2;                         // scope 1 at $DIR/lower_intrinsics.rs:8:48: 8:49
--         _6 = wrapping_sub::<T>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
+-         _6 = wrapping_sub::<i32>(move _7, move _8) -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:8:14: 8:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_sub::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_sub::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _6 = Sub(move _7, move _8);      // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
 +         goto -> bb2;                     // scope 1 at $DIR/lower_intrinsics.rs:8:14: 8:50
       }
@@ -62,10 +62,10 @@
           _10 = _1;                        // scope 2 at $DIR/lower_intrinsics.rs:9:45: 9:46
           StorageLive(_11);                // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49
           _11 = _2;                        // scope 2 at $DIR/lower_intrinsics.rs:9:48: 9:49
--         _9 = wrapping_mul::<T>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
+-         _9 = wrapping_mul::<i32>(move _10, move _11) -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 -                                          // mir::Constant
 -                                          // + span: $DIR/lower_intrinsics.rs:9:14: 9:44
--                                          // + literal: Const { ty: extern "rust-intrinsic" fn(T, T) -> T {wrapping_mul::<T>}, val: Value(Scalar(<ZST>)) }
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> i32 {wrapping_mul::<i32>}, val: Value(Scalar(<ZST>)) }
 +         _9 = Mul(move _10, move _11);    // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
 +         goto -> bb3;                     // scope 2 at $DIR/lower_intrinsics.rs:9:14: 9:50
       }
@@ -73,7 +73,7 @@
       bb3: {
           StorageDead(_11);                // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50
           StorageDead(_10);                // scope 2 at $DIR/lower_intrinsics.rs:9:49: 9:50
-          _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:6:38: 10:2
+          _0 = const ();                   // scope 0 at $DIR/lower_intrinsics.rs:6:33: 10:2
           StorageDead(_9);                 // scope 2 at $DIR/lower_intrinsics.rs:10:1: 10:2
           StorageDead(_6);                 // scope 1 at $DIR/lower_intrinsics.rs:10:1: 10:2
           StorageDead(_3);                 // scope 0 at $DIR/lower_intrinsics.rs:10:1: 10:2
diff --git a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
index 5afffff..c53c987 100644
--- a/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
+++ b/src/test/run-make/rustdoc-scrape-examples-ordering/src/lib.rs
@@ -1,7 +1,6 @@
 // @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
 // @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
-// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1'
-// @has foobar/fn.ok.html '//*[@class="highlight"]' '2'
-// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' 'ok'
+// @has foobar/fn.ok.html '//*[@class="highlight"]' 'ok'
 
 pub fn ok(_x: i32) {}
diff --git a/src/test/run-make/translation/Makefile b/src/test/run-make/translation/Makefile
index 22a3bf5..bfff75e 100644
--- a/src/test/run-make/translation/Makefile
+++ b/src/test/run-make/translation/Makefile
@@ -15,7 +15,9 @@
 custom: basic-translation.rs basic-translation.ftl
 	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/basic-translation.ftl 2>&1 | grep "this is a test message"
 
-# Make a local copy of the sysroot and add the custom locale to it.
+# Check that a locale can be loaded from the sysroot given a language
+# identifier by making a local copy of the sysroot and adding the custom locale
+# to it.
 sysroot: basic-translation.rs basic-translation.ftl
 	mkdir $(FAKEROOT)
 	ln -s $(SYSROOT)/* $(FAKEROOT)
@@ -31,3 +33,27 @@
 	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
 	ln -s $(CURDIR)/basic-translation.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
 	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | grep "this is a test message"
+
+# Check that the compiler errors out when the sysroot requested cannot be
+# found. This test might start failing if there actually exists a Klingon
+# translation of rustc's error messages.
+sysroot-missing: 
+	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 || grep "missing locale directory"
+
+# Check that the compiler errors out when the sysroot requested cannot be
+# found. This test might start failing if there actually exists a Klingon
+# translation of rustc's error messages.
+sysroot-invalid: basic-translation.rs basic-translation.ftl
+	mkdir $(FAKEROOT)
+	ln -s $(SYSROOT)/* $(FAKEROOT)
+	rm -f $(FAKEROOT)/lib
+	mkdir $(FAKEROOT)/lib
+	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
+	rm -f $(FAKEROOT)/lib/rustlib
+	mkdir $(FAKEROOT)/lib/rustlib
+	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
+	rm -f $(FAKEROOT)/lib/rustlib/src
+	mkdir $(FAKEROOT)/lib/rustlib/src
+	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
+	touch $(FAKEROOT)/share/locale/zh-CN/
+	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 || grep "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.rs b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
new file mode 100644
index 0000000..4cd9993
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.rs
@@ -0,0 +1,28 @@
+// only-windows
+// There's a parallel generic version of this test for non-windows platforms.
+
+// Issue #51162: A failed doctest was not printing its stdout/stderr
+// FIXME: if/when the output of the test harness can be tested on its own, this test should be
+// adapted to use that, and that normalize line can go away
+
+// compile-flags:--test --test-args --test-threads=1
+// rustc-env:RUST_BACKTRACE=0
+// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
+// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"
+// failure-status: 101
+
+// doctest fails at runtime
+/// ```
+/// println!("stdout 1");
+/// eprintln!("stderr 1");
+/// println!("stdout 2");
+/// eprintln!("stderr 2");
+/// panic!("oh no");
+/// ```
+pub struct SomeStruct;
+
+// doctest fails at compile time
+/// ```
+/// no
+/// ```
+pub struct OtherStruct;
diff --git a/src/test/rustdoc-ui/failed-doctest-output-windows.stdout b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
new file mode 100644
index 0000000..6c14705
--- /dev/null
+++ b/src/test/rustdoc-ui/failed-doctest-output-windows.stdout
@@ -0,0 +1,39 @@
+
+running 2 tests
+test $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) ... FAILED
+
+failures:
+
+---- $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25) stdout ----
+error[E0425]: cannot find value `no` in this scope
+  --> $DIR/failed-doctest-output-windows.rs:26:1
+   |
+LL | no
+   | ^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
+Couldn't compile the test.
+---- $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit code: 101).
+
+stdout:
+stdout 1
+stdout 2
+
+stderr:
+stderr 1
+stderr 2
+thread 'main' panicked at 'oh no', $DIR/failed-doctest-output-windows.rs:7:1
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+
+
+failures:
+    $DIR/failed-doctest-output-windows.rs - OtherStruct (line 25)
+    $DIR/failed-doctest-output-windows.rs - SomeStruct (line 15)
+
+test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs
index 92473b4..42de954 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.rs
+++ b/src/test/rustdoc-ui/failed-doctest-output.rs
@@ -1,3 +1,6 @@
+// ignore-windows
+// There's a parallel version of this test for Windows.
+
 // Issue #51162: A failed doctest was not printing its stdout/stderr
 // FIXME: if/when the output of the test harness can be tested on its own, this test should be
 // adapted to use that, and that normalize line can go away
diff --git a/src/test/rustdoc-ui/failed-doctest-output.stdout b/src/test/rustdoc-ui/failed-doctest-output.stdout
index 6dfe648..630198a 100644
--- a/src/test/rustdoc-ui/failed-doctest-output.stdout
+++ b/src/test/rustdoc-ui/failed-doctest-output.stdout
@@ -1,13 +1,13 @@
 
 running 2 tests
-test $DIR/failed-doctest-output.rs - OtherStruct (line 22) ... FAILED
-test $DIR/failed-doctest-output.rs - SomeStruct (line 12) ... FAILED
+test $DIR/failed-doctest-output.rs - OtherStruct (line 25) ... FAILED
+test $DIR/failed-doctest-output.rs - SomeStruct (line 15) ... FAILED
 
 failures:
 
----- $DIR/failed-doctest-output.rs - OtherStruct (line 22) stdout ----
+---- $DIR/failed-doctest-output.rs - OtherStruct (line 25) stdout ----
 error[E0425]: cannot find value `no` in this scope
-  --> $DIR/failed-doctest-output.rs:23:1
+  --> $DIR/failed-doctest-output.rs:26:1
    |
 LL | no
    | ^^ not found in this scope
@@ -16,8 +16,8 @@
 
 For more information about this error, try `rustc --explain E0425`.
 Couldn't compile the test.
----- $DIR/failed-doctest-output.rs - SomeStruct (line 12) stdout ----
-Test executable failed (exit code 101).
+---- $DIR/failed-doctest-output.rs - SomeStruct (line 15) stdout ----
+Test executable failed (exit status: 101).
 
 stdout:
 stdout 1
@@ -32,8 +32,8 @@
 
 
 failures:
-    $DIR/failed-doctest-output.rs - OtherStruct (line 22)
-    $DIR/failed-doctest-output.rs - SomeStruct (line 12)
+    $DIR/failed-doctest-output.rs - OtherStruct (line 25)
+    $DIR/failed-doctest-output.rs - SomeStruct (line 15)
 
 test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
 
diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs
index ff7fd66..0ac6dc7 100644
--- a/src/test/rustdoc/assoc-consts.rs
+++ b/src/test/rustdoc/assoc-consts.rs
@@ -1,8 +1,8 @@
 pub trait Foo {
     // @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
-    //      'const FOO: usize;'
+    //      'const FOO: usize = 13usize;'
     // @has - '//*[@id="associatedconstant.FOO"]' 'const FOO: usize'
-    const FOO: usize = 12;
+    const FOO: usize = 12 + 1;
     // @has - '//*[@id="associatedconstant.FOO_NO_DEFAULT"]' 'const FOO_NO_DEFAULT: bool'
     const FOO_NO_DEFAULT: bool;
     // @!has - FOO_HIDDEN
diff --git a/src/test/rustdoc/extern-default-method.no_href_on_anchor.html b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html
new file mode 100644
index 0000000..dab0a64
--- /dev/null
+++ b/src/test/rustdoc/extern-default-method.no_href_on_anchor.html
@@ -0,0 +1 @@
+<a class="fnname">provided</a>(&amp;self)
\ No newline at end of file
diff --git a/src/test/rustdoc/extern-default-method.rs b/src/test/rustdoc/extern-default-method.rs
index 93cf163..8139f5b 100644
--- a/src/test/rustdoc/extern-default-method.rs
+++ b/src/test/rustdoc/extern-default-method.rs
@@ -1,9 +1,23 @@
 // aux-build:rustdoc-extern-default-method.rs
 // ignore-cross-compile
+// ignore-tidy-linelength
 
 extern crate rustdoc_extern_default_method as ext;
 
+// For this test, the dependency is compiled but not documented.
+//
+// Still, the struct from the external crate and its impl should be documented since
+// the struct is re-exported from this crate.
+// However, the method in the trait impl should *not* have a link (an `href` attribute) to
+// its corresponding item in the trait declaration since it would otherwise be broken.
+//
+// In older versions of rustdoc, the impl item (`a[@class="fnname"]`) used to link to
+// `#method.provided` – i.e. "to itself". Put in quotes since that was actually incorrect in
+// general: If the type `Struct` also had an inherent method called `provided`, the impl item
+// would link to that one even though those two methods are distinct items!
+
 // @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
-// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
+// @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]' 1
+// @snapshot no_href_on_anchor - '//*[@id="method.provided"]//a[@class="fnname"]'
 // @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
 pub use ext::Struct;
diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs
index de053d7..c7ce71b 100644
--- a/src/test/rustdoc/intra-doc/prim-self.rs
+++ b/src/test/rustdoc/intra-doc/prim-self.rs
@@ -5,6 +5,7 @@
 #![feature(no_core)]
 #![feature(rustdoc_internals)]
 #![feature(inherent_associated_types)]
+#![feature(lang_items)]
 #![no_core]
 
 /// [Self::f]
@@ -35,3 +36,6 @@ mod usize {}
 impl S {
     pub fn f() {}
 }
+
+#[lang = "sized"]
+pub trait Sized {}
diff --git a/src/test/rustdoc/sidebar-items.rs b/src/test/rustdoc/sidebar-items.rs
index 375cad9..b5b681a 100644
--- a/src/test/rustdoc/sidebar-items.rs
+++ b/src/test/rustdoc/sidebar-items.rs
@@ -1,3 +1,4 @@
+#![feature(associated_type_defaults)]
 #![crate_name = "foo"]
 
 // @has foo/trait.Foo.html
@@ -5,12 +6,18 @@
 // @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
 // @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
-// @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants'
+// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-consts"]' 'Required Associated Constants'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'FOO'
+// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-consts"]' 'Provided Associated Constants'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
-// @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types'
+// @has - '//*[@class="sidebar-title"]/a[@href="#required-associated-types"]' 'Required Associated Types'
 // @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
+// @has - '//*[@class="sidebar-title"]/a[@href="#provided-associated-types"]' 'Provided Associated Types'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Extra'
 pub trait Foo {
+    const FOO: usize;
     const BAR: u32 = 0;
+    type Extra: Copy = ();
     type Output: ?Sized;
 
     fn foo() {}
diff --git a/src/test/ui/box/issue-82446.rs b/src/test/ui/box/issue-82446.rs
new file mode 100644
index 0000000..2960f7f
--- /dev/null
+++ b/src/test/ui/box/issue-82446.rs
@@ -0,0 +1,15 @@
+// https://github.com/rust-lang/rust/issues/82446
+// Spurious 'help: store this in the heap' regression test
+trait MyTrait {}
+
+struct Foo {
+    val: Box<dyn MyTrait>
+}
+
+fn make_it(val: &Box<dyn MyTrait>) {
+    Foo {
+        val //~ ERROR [E0308]
+    };
+}
+
+fn main() {}
diff --git a/src/test/ui/box/issue-82446.stderr b/src/test/ui/box/issue-82446.stderr
new file mode 100644
index 0000000..0374737
--- /dev/null
+++ b/src/test/ui/box/issue-82446.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-82446.rs:11:9
+   |
+LL |         val
+   |         ^^^ expected struct `Box`, found reference
+   |
+   = note: expected struct `Box<(dyn MyTrait + 'static)>`
+           found reference `&Box<(dyn MyTrait + 'static)>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/cast/cast-macro-lhs.rs b/src/test/ui/cast/cast-macro-lhs.rs
new file mode 100644
index 0000000..b509b32
--- /dev/null
+++ b/src/test/ui/cast/cast-macro-lhs.rs
@@ -0,0 +1,12 @@
+// Test to make sure we suggest "consider casting" on the right span
+
+macro_rules! foo {
+    () => { 0 }
+}
+
+fn main() {
+    let x = foo!() as *const [u8];
+    //~^ ERROR cannot cast `usize` to a pointer that is wide
+    //~| NOTE creating a `*const [u8]` requires both an address and a length
+    //~| NOTE consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+}
diff --git a/src/test/ui/cast/cast-macro-lhs.stderr b/src/test/ui/cast/cast-macro-lhs.stderr
new file mode 100644
index 0000000..db7ce57
--- /dev/null
+++ b/src/test/ui/cast/cast-macro-lhs.stderr
@@ -0,0 +1,11 @@
+error[E0606]: cannot cast `usize` to a pointer that is wide
+  --> $DIR/cast-macro-lhs.rs:8:23
+   |
+LL |     let x = foo!() as *const [u8];
+   |             ------    ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length
+   |             |
+   |             consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
index b1141cf..9f6c7cc 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr
@@ -7,12 +7,5 @@
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter
-  --> $DIR/issue-63322-forbid-dyn.rs:9:18
-   |
-LL | fn test<const T: &'static dyn A>() {
-   |                  ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq`
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0741`.
diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
index 01a6caa..116c3fc 100644
--- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
+++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs
@@ -7,7 +7,7 @@ trait A {}
 impl A for B {}
 
 fn test<const T: &'static dyn A>() {
-    //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used
+    //[full]~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used
     //[min]~^^ ERROR `&'static (dyn A + 'static)` is forbidden
     unimplemented!()
 }
diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr
index 0e3c988..276ebf3 100644
--- a/src/test/ui/const-generics/nested-type.min.stderr
+++ b/src/test/ui/const-generics/nested-type.min.stderr
@@ -14,14 +14,5 @@
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
-  --> $DIR/nested-type.rs:15:5
-   |
-LL |     Foo::<17>::value()
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+error: aborting due to previous error
 
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0015`.
diff --git a/src/test/ui/const-generics/nested-type.rs b/src/test/ui/const-generics/nested-type.rs
index 5240f5c..742340f 100644
--- a/src/test/ui/const-generics/nested-type.rs
+++ b/src/test/ui/const-generics/nested-type.rs
@@ -13,7 +13,7 @@ fn value() -> usize {
     }
 
     Foo::<17>::value()
-    //~^ ERROR cannot call non-const fn
+    //[full]~^ ERROR cannot call non-const fn
 }]>;
 
 fn main() {}
diff --git a/src/test/ui/consts/std/alloc.32bit.stderr b/src/test/ui/consts/std/alloc.32bit.stderr
index 1490314..138eb69 100644
--- a/src/test/ui/consts/std/alloc.32bit.stderr
+++ b/src/test/ui/consts/std/alloc.32bit.stderr
@@ -2,7 +2,7 @@
   --> $DIR/alloc.rs:9:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
@@ -13,7 +13,7 @@
   --> $DIR/alloc.rs:13:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x00000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 8, align: 4) {
diff --git a/src/test/ui/consts/std/alloc.64bit.stderr b/src/test/ui/consts/std/alloc.64bit.stderr
index 58349fe..ecb08c3 100644
--- a/src/test/ui/consts/std/alloc.64bit.stderr
+++ b/src/test/ui/consts/std/alloc.64bit.stderr
@@ -2,7 +2,7 @@
   --> $DIR/alloc.rs:9:1
    |
 LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000000, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
@@ -13,7 +13,7 @@
   --> $DIR/alloc.rs:13:1
    |
 LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) };
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align_.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .align.0.<enum-tag>: encountered 0x0000000000000003, but expected a valid enum tag
    |
    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
    = note: the raw bytes of the constant (size: 16, align: 8) {
diff --git a/src/test/ui/impl-trait/auto-trait.rs b/src/test/ui/impl-trait/auto-trait.rs
index 35994e4..afa9564 100644
--- a/src/test/ui/impl-trait/auto-trait.rs
+++ b/src/test/ui/impl-trait/auto-trait.rs
@@ -20,6 +20,7 @@ impl<T: Send> AnotherTrait for T {}
 // in the future.)
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
+    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/auto-trait.stderr b/src/test/ui/impl-trait/auto-trait.stderr
index 8100941..3b360f4 100644
--- a/src/test/ui/impl-trait/auto-trait.stderr
+++ b/src/test/ui/impl-trait/auto-trait.stderr
@@ -1,3 +1,15 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/auto-trait.rs:21:25
+   |
+LL | impl AnotherTrait for D<OpaqueType> {
+   |                         ^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/auto-trait.rs:7:19
+   |
+LL | type OpaqueType = impl OpaqueTrait;
+   |                   ^^^^^^^^^^^^^^^^
+
 error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
   --> $DIR/auto-trait.rs:21:1
    |
@@ -7,6 +19,6 @@
 LL | impl AnotherTrait for D<OpaqueType> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `D<OpaqueType>`
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/negative-reasoning.rs b/src/test/ui/impl-trait/negative-reasoning.rs
index 70e24a3..da69bb3 100644
--- a/src/test/ui/impl-trait/negative-reasoning.rs
+++ b/src/test/ui/impl-trait/negative-reasoning.rs
@@ -18,6 +18,7 @@ impl<T: std::fmt::Debug> AnotherTrait for T {}
 // This is in error, because we cannot assume that `OpaqueType: !Debug`
 impl AnotherTrait for D<OpaqueType> {
     //~^ ERROR conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
+    //~| ERROR cannot implement trait on type alias impl trait
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/negative-reasoning.stderr b/src/test/ui/impl-trait/negative-reasoning.stderr
index 6b8cc9e..98f9fbd 100644
--- a/src/test/ui/impl-trait/negative-reasoning.stderr
+++ b/src/test/ui/impl-trait/negative-reasoning.stderr
@@ -1,3 +1,15 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/negative-reasoning.rs:19:25
+   |
+LL | impl AnotherTrait for D<OpaqueType> {
+   |                         ^^^^^^^^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/negative-reasoning.rs:7:19
+   |
+LL | type OpaqueType = impl OpaqueTrait;
+   |                   ^^^^^^^^^^^^^^^^
+
 error[E0119]: conflicting implementations of trait `AnotherTrait` for type `D<OpaqueType>`
   --> $DIR/negative-reasoning.rs:19:1
    |
@@ -9,6 +21,6 @@
    |
    = note: upstream crates may add a new impl of trait `std::fmt::Debug` for type `OpaqueType` in future versions
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0119`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
index 6b200d7..621c4ea 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs
@@ -5,13 +5,14 @@
 struct Bar;
 
 impl PartialEq<(Foo, i32)> for Bar {
+//~^ ERROR cannot implement trait on type alias impl trait
     fn eq(&self, _other: &(Foo, i32)) -> bool {
         true
     }
 }
 
 fn foo() -> Foo {
-    Bar //~ ERROR can't compare `Bar` with `(Bar, i32)`
+    Bar
 }
 
 fn main() {}
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
index 6cd63db..2ef1697 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle-2.stderr
@@ -1,12 +1,14 @@
-error[E0277]: can't compare `Bar` with `(Bar, i32)`
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:14:5
+error: cannot implement trait on type alias impl trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:7:17
    |
-LL |     Bar
-   |     ^^^ no implementation for `Bar == (Bar, i32)`
+LL | impl PartialEq<(Foo, i32)> for Bar {
+   |                 ^^^
    |
-   = help: the trait `PartialEq<(Bar, i32)>` is not implemented for `Bar`
-   = help: the trait `PartialEq<(Foo, i32)>` is implemented for `Bar`
+note: type alias impl trait defined here
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle-2.rs:3:12
+   |
+LL | type Foo = impl PartialEq<(Foo, i32)>;
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
index 6aa832c..df7966f 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.rs
@@ -2,7 +2,6 @@
 
 mod a {
     type Foo = impl PartialEq<(Foo, i32)>;
-    //~^ ERROR unconstrained opaque type
 
     struct Bar;
 
@@ -15,13 +14,12 @@ fn eq(&self, _other: &(Foo, i32)) -> bool {
 
 mod b {
     type Foo = impl PartialEq<(Foo, i32)>;
-    //~^ ERROR unconstrained opaque type
 
     struct Bar;
 
     impl PartialEq<(Foo, i32)> for Bar {
+        //~^ ERROR cannot implement trait on type alias impl trait
         fn eq(&self, _other: &(Bar, i32)) -> bool {
-            //~^ ERROR impl has stricter requirements than trait
             true
         }
     }
diff --git a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
index 19d5cdb..6cd63dc 100644
--- a/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
+++ b/src/test/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr
@@ -1,25 +1,14 @@
-error: unconstrained opaque type
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:4:16
+error: cannot implement trait on type alias impl trait
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:20:21
+   |
+LL |     impl PartialEq<(Foo, i32)> for Bar {
+   |                     ^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:16:16
    |
 LL |     type Foo = impl PartialEq<(Foo, i32)>;
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `Foo` must be used in combination with a concrete type within the same module
 
-error: unconstrained opaque type
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:17:16
-   |
-LL |     type Foo = impl PartialEq<(Foo, i32)>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `Foo` must be used in combination with a concrete type within the same module
+error: aborting due to previous error
 
-error[E0276]: impl has stricter requirements than trait
-  --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:23:9
-   |
-LL |         fn eq(&self, _other: &(Bar, i32)) -> bool {
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `b::Bar: PartialEq<(b::Bar, i32)>`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0276`.
diff --git a/src/test/ui/issues/issue-70093.rs b/src/test/ui/issues/issue-70093.rs
index fbe68fb..86459dc 100644
--- a/src/test/ui/issues/issue-70093.rs
+++ b/src/test/ui/issues/issue-70093.rs
@@ -2,6 +2,7 @@
 // compile-flags: -Zlink-native-libraries=no -Cdefault-linker-libraries=yes
 // ignore-windows - this will probably only work on unixish systems
 // ignore-fuchsia - missing __libc_start_main for some reason (#84733)
+// ignore-cross-compile - default-linker-libraries=yes doesn't play well with cross compiling
 
 #[link(name = "some-random-non-existent-library", kind = "static")]
 extern "C" {}
diff --git a/src/test/ui/lint/unused/unused-attr-duplicate.rs b/src/test/ui/lint/unused/unused-attr-duplicate.rs
index 074d5a9..692617e 100644
--- a/src/test/ui/lint/unused/unused-attr-duplicate.rs
+++ b/src/test/ui/lint/unused/unused-attr-duplicate.rs
@@ -13,9 +13,6 @@
 #![crate_name = "unused_attr_duplicate"]
 #![crate_name = "unused_attr_duplicate2"] //~ ERROR unused attribute
 //~^ WARN this was previously accepted
-#![crate_type = "bin"]
-#![crate_type = "rlib"] //~ ERROR unused attribute
-//~^ WARN this was previously accepted
 #![recursion_limit = "128"]
 #![recursion_limit = "256"] //~ ERROR unused attribute
 //~^ WARN this was previously accepted
diff --git a/src/test/ui/lint/unused/unused-attr-duplicate.stderr b/src/test/ui/lint/unused/unused-attr-duplicate.stderr
index d4305ad..f592323 100644
--- a/src/test/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/src/test/ui/lint/unused/unused-attr-duplicate.stderr
@@ -1,5 +1,5 @@
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:36:1
+  --> $DIR/unused-attr-duplicate.rs:33:1
    |
 LL | #[no_link]
    | ^^^^^^^^^^ help: remove this attribute
@@ -10,180 +10,180 @@
 LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:35:1
+  --> $DIR/unused-attr-duplicate.rs:32:1
    |
 LL | #[no_link]
    | ^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:40:1
+  --> $DIR/unused-attr-duplicate.rs:37:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:39:1
+  --> $DIR/unused-attr-duplicate.rs:36:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:50:1
+  --> $DIR/unused-attr-duplicate.rs:47:1
    |
 LL | #[path = "bar.rs"]
    | ^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:49:1
+  --> $DIR/unused-attr-duplicate.rs:46:1
    |
 LL | #[path = "auxiliary/lint_unused_extern_crate.rs"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:56:1
+  --> $DIR/unused-attr-duplicate.rs:53:1
    |
 LL | #[ignore = "some text"]
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:55:1
+  --> $DIR/unused-attr-duplicate.rs:52:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:58:1
+  --> $DIR/unused-attr-duplicate.rs:55:1
    |
 LL | #[should_panic(expected = "values don't match")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:57:1
+  --> $DIR/unused-attr-duplicate.rs:54:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:63:1
+  --> $DIR/unused-attr-duplicate.rs:60:1
    |
 LL | #[must_use = "some message"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:62:1
+  --> $DIR/unused-attr-duplicate.rs:59:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:69:1
+  --> $DIR/unused-attr-duplicate.rs:66:1
    |
 LL | #[non_exhaustive]
    | ^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:68:1
+  --> $DIR/unused-attr-duplicate.rs:65:1
    |
 LL | #[non_exhaustive]
    | ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:73:1
+  --> $DIR/unused-attr-duplicate.rs:70:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:72:1
+  --> $DIR/unused-attr-duplicate.rs:69:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:77:1
+  --> $DIR/unused-attr-duplicate.rs:74:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:76:1
+  --> $DIR/unused-attr-duplicate.rs:73:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:80:1
+  --> $DIR/unused-attr-duplicate.rs:77:1
    |
 LL | #[cold]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:79:1
+  --> $DIR/unused-attr-duplicate.rs:76:1
    |
 LL | #[cold]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:82:1
+  --> $DIR/unused-attr-duplicate.rs:79:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:81:1
+  --> $DIR/unused-attr-duplicate.rs:78:1
    |
 LL | #[track_caller]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:95:1
+  --> $DIR/unused-attr-duplicate.rs:92:1
    |
 LL | #[export_name = "exported_symbol_name"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:97:1
+  --> $DIR/unused-attr-duplicate.rs:94:1
    |
 LL | #[export_name = "exported_symbol_name2"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:101:1
+  --> $DIR/unused-attr-duplicate.rs:98:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:100:1
+  --> $DIR/unused-attr-duplicate.rs:97:1
    |
 LL | #[no_mangle]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:105:1
+  --> $DIR/unused-attr-duplicate.rs:102:1
    |
 LL | #[used]
    | ^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:104:1
+  --> $DIR/unused-attr-duplicate.rs:101:1
    |
 LL | #[used]
    | ^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:89:5
+  --> $DIR/unused-attr-duplicate.rs:86:5
    |
 LL |     #[link_name = "this_does_not_exist"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:91:5
+  --> $DIR/unused-attr-duplicate.rs:88:5
    |
 LL |     #[link_name = "rust_dbg_extern_identity_u32"]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,102 +205,89 @@
 error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:17:1
    |
-LL | #![crate_type = "rlib"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:16:1
-   |
-LL | #![crate_type = "bin"]
-   | ^^^^^^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:20:1
-   |
 LL | #![recursion_limit = "256"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:19:1
+  --> $DIR/unused-attr-duplicate.rs:16:1
    |
 LL | #![recursion_limit = "128"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:23:1
+  --> $DIR/unused-attr-duplicate.rs:20:1
    |
 LL | #![type_length_limit = "1"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:22:1
+  --> $DIR/unused-attr-duplicate.rs:19:1
    |
 LL | #![type_length_limit = "1048576"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:26:1
+  --> $DIR/unused-attr-duplicate.rs:23:1
    |
 LL | #![no_std]
    | ^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:25:1
+  --> $DIR/unused-attr-duplicate.rs:22:1
    |
 LL | #![no_std]
    | ^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:28:1
+  --> $DIR/unused-attr-duplicate.rs:25:1
    |
 LL | #![no_implicit_prelude]
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:27:1
+  --> $DIR/unused-attr-duplicate.rs:24:1
    |
 LL | #![no_implicit_prelude]
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:30:1
+  --> $DIR/unused-attr-duplicate.rs:27:1
    |
 LL | #![windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:29:1
+  --> $DIR/unused-attr-duplicate.rs:26:1
    |
 LL | #![windows_subsystem = "console"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:33:1
+  --> $DIR/unused-attr-duplicate.rs:30:1
    |
 LL | #![no_builtins]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:32:1
+  --> $DIR/unused-attr-duplicate.rs:29:1
    |
 LL | #![no_builtins]
    | ^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:43:5
+  --> $DIR/unused-attr-duplicate.rs:40:5
    |
 LL |     #[macro_export]
    |     ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:42:5
+  --> $DIR/unused-attr-duplicate.rs:39:5
    |
 LL |     #[macro_export]
    |     ^^^^^^^^^^^^^^^
 
-error: aborting due to 24 previous errors
+error: aborting due to 23 previous errors
 
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
index d31046c..fb6cf7e 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed
@@ -69,4 +69,18 @@
     (t, t) //~ use of moved value: `t`
 }
 
+#[rustfmt::skip]
+fn existing_colon<T: Copy>(t: T) {
+    //~^ HELP consider restricting type parameter `T`
+    [t, t]; //~ use of moved value: `t`
+}
+
+fn existing_colon_in_where<T>(t: T)
+where
+    T: Copy,
+    //~^ HELP consider further restricting this bound
+{
+    [t, t]; //~ use of moved value: `t`
+}
+
 fn main() {}
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
index 7cc5189..cadbf2a 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs
@@ -69,4 +69,18 @@ fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>)
     (t, t) //~ use of moved value: `t`
 }
 
+#[rustfmt::skip]
+fn existing_colon<T:>(t: T) {
+    //~^ HELP consider restricting type parameter `T`
+    [t, t]; //~ use of moved value: `t`
+}
+
+fn existing_colon_in_where<T>(t: T)
+where
+    T:,
+    //~^ HELP consider further restricting this bound
+{
+    [t, t]; //~ use of moved value: `t`
+}
+
 fn main() {}
diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
index 8e72697..f525208 100644
--- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
+++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr
@@ -142,6 +142,38 @@
 LL |     T: B + Trait + Copy,
    |          ++++++++++++++
 
-error: aborting due to 9 previous errors
+error[E0382]: use of moved value: `t`
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9
+   |
+LL | fn existing_colon_in_where<T>(t: T)
+   |                               - move occurs because `t` has type `T`, which does not implement the `Copy` trait
+...
+LL |     [t, t];
+   |      -  ^ value used here after move
+   |      |
+   |      value moved here
+   |
+help: consider further restricting this bound
+   |
+LL |     T: Copy,
+   |        ++++
+
+error[E0382]: use of moved value: `t`
+  --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9
+   |
+LL | fn existing_colon<T:>(t: T) {
+   |                       - move occurs because `t` has type `T`, which does not implement the `Copy` trait
+LL |
+LL |     [t, t];
+   |      -  ^ value used here after move
+   |      |
+   |      value moved here
+   |
+help: consider restricting type parameter `T`
+   |
+LL | fn existing_colon<T: Copy>(t: T) {
+   |                      ++++
+
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/pattern/issue-95878.rs b/src/test/ui/pattern/issue-95878.rs
new file mode 100644
index 0000000..f598144
--- /dev/null
+++ b/src/test/ui/pattern/issue-95878.rs
@@ -0,0 +1,12 @@
+struct Foo<'a>(&'a ());
+
+impl<'a> Foo<'a> {
+    fn spam(&mut self, baz: &mut Vec<u32>) {
+        match 15 {
+            ref Self => (),
+            //~^ ERROR expected identifier, found keyword `Self`
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/pattern/issue-95878.stderr b/src/test/ui/pattern/issue-95878.stderr
new file mode 100644
index 0000000..e0eea06
--- /dev/null
+++ b/src/test/ui/pattern/issue-95878.stderr
@@ -0,0 +1,8 @@
+error: expected identifier, found keyword `Self`
+  --> $DIR/issue-95878.rs:6:17
+   |
+LL |             ref Self => (),
+   |                 ^^^^ expected identifier, found keyword
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/privacy/restricted/relative-2018.rs b/src/test/ui/privacy/restricted/relative-2018.rs
index 69b7c1e..954169a 100644
--- a/src/test/ui/privacy/restricted/relative-2018.rs
+++ b/src/test/ui/privacy/restricted/relative-2018.rs
@@ -7,7 +7,7 @@ mod m {
     pub(in ::core) struct S4;
     //~^ ERROR visibilities can only be restricted to ancestor modules
     pub(in a::b) struct S5;
-    //~^ ERROR relative paths are not supported in visibilities on 2018 edition
+    //~^ ERROR relative paths are not supported in visibilities in 2018 edition or later
 }
 
 fn main() {}
diff --git a/src/test/ui/privacy/restricted/relative-2018.stderr b/src/test/ui/privacy/restricted/relative-2018.stderr
index 54fee08..dec0d51 100644
--- a/src/test/ui/privacy/restricted/relative-2018.stderr
+++ b/src/test/ui/privacy/restricted/relative-2018.stderr
@@ -4,7 +4,7 @@
 LL |     pub(in ::core) struct S4;
    |            ^^^^^^
 
-error: relative paths are not supported in visibilities on 2018 edition
+error: relative paths are not supported in visibilities in 2018 edition or later
   --> $DIR/relative-2018.rs:9:12
    |
 LL |     pub(in a::b) struct S5;
diff --git a/src/test/ui/traits/alias/issue-83613.stderr b/src/test/ui/traits/alias/issue-83613.stderr
index 4f19e66..bbc240b 100644
--- a/src/test/ui/traits/alias/issue-83613.stderr
+++ b/src/test/ui/traits/alias/issue-83613.stderr
@@ -1,8 +1,8 @@
 error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-83613.rs:10:1
+  --> $DIR/issue-83613.rs:10:23
    |
 LL | impl AnotherTrait for OpaqueType {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                       ^^^^^^^^^^
    |
 note: type alias impl trait defined here
   --> $DIR/issue-83613.rs:4:19
diff --git a/src/test/ui/traits/issue-95898.rs b/src/test/ui/traits/issue-95898.rs
new file mode 100644
index 0000000..41a20b8
--- /dev/null
+++ b/src/test/ui/traits/issue-95898.rs
@@ -0,0 +1,9 @@
+// Test for #95898: The trait suggestion had an extra `:` after the trait.
+// edition:2021
+
+fn foo<T:>(t: T) {
+    t.clone();
+    //~^ ERROR no method named `clone` found for type parameter `T` in the current scope
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-95898.stderr b/src/test/ui/traits/issue-95898.stderr
new file mode 100644
index 0000000..d7d4790
--- /dev/null
+++ b/src/test/ui/traits/issue-95898.stderr
@@ -0,0 +1,15 @@
+error[E0599]: no method named `clone` found for type parameter `T` in the current scope
+  --> $DIR/issue-95898.rs:5:7
+   |
+LL |     t.clone();
+   |       ^^^^^ method not found in `T`
+   |
+   = help: items from traits can only be used if the type parameter is bounded by the trait
+help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it:
+   |
+LL | fn foo<T: Clone>(t: T) {
+   |        ~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-65384.stderr b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
index 27680f0..41bcea2 100644
--- a/src/test/ui/type-alias-impl-trait/issue-65384.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-65384.stderr
@@ -1,8 +1,8 @@
 error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-65384.rs:10:1
+  --> $DIR/issue-65384.rs:10:18
    |
 LL | impl MyTrait for Bar {}
-   | ^^^^^^^^^^^^^^^^^^^^
+   |                  ^^^
    |
 note: type alias impl trait defined here
   --> $DIR/issue-65384.rs:8:12
diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
index 8689ee5..2d4a685 100644
--- a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr
@@ -1,8 +1,8 @@
 error: cannot implement trait on type alias impl trait
-  --> $DIR/issue-76202-trait-impl-for-tait.rs:16:1
+  --> $DIR/issue-76202-trait-impl-for-tait.rs:16:15
    |
 LL | impl Test for F {
-   | ^^^^^^^^^^^^^^^
+   |               ^
    |
 note: type alias impl trait defined here
   --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
new file mode 100644
index 0000000..fa25d8f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs
@@ -0,0 +1,23 @@
+// Regression test for issues #84660 and #86411: both are variations on #76202.
+// Tests that we don't ICE when we have an opaque type appearing anywhere in an impl header.
+
+#![feature(type_alias_impl_trait)]
+
+trait Foo {}
+impl Foo for () {}
+type Bar = impl Foo;
+fn _defining_use() -> Bar {}
+
+trait TraitArg<T> {
+    fn f();
+}
+
+impl TraitArg<Bar> for () { //~ ERROR cannot implement trait
+    fn f() {
+        println!("ho");
+    }
+}
+
+fn main() {
+    <() as TraitArg<Bar>>::f();
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
new file mode 100644
index 0000000..bb70d07
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.stderr
@@ -0,0 +1,14 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/issue-84660-trait-impl-for-tait.rs:15:15
+   |
+LL | impl TraitArg<Bar> for () {
+   |               ^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/issue-84660-trait-impl-for-tait.rs:8:12
+   |
+LL | type Bar = impl Foo;
+   |            ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
new file mode 100644
index 0000000..f12d1b6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
@@ -0,0 +1,41 @@
+// Another example from issue #84660, this time weaponized as a safe transmute: an opaque type in an
+// impl header being accepted was used to create unsoundness.
+
+#![feature(type_alias_impl_trait)]
+
+trait Foo {}
+impl Foo for () {}
+type Bar = impl Foo;
+fn _defining_use() -> Bar {}
+
+trait Trait<T, In> {
+    type Out;
+    fn convert(i: In) -> Self::Out;
+}
+
+impl<In, Out> Trait<Bar, In> for Out { //~ ERROR cannot implement trait
+    type Out = Out;
+    fn convert(_i: In) -> Self::Out {
+        unreachable!();
+    }
+}
+
+impl<In, Out> Trait<(), In> for Out {
+    type Out = In;
+    fn convert(i: In) -> Self::Out {
+        i
+    }
+}
+
+fn transmute<In, Out>(i: In) -> Out {
+    <Out as Trait<Bar, In>>::convert(i)
+}
+
+fn main() {
+    let d;
+    {
+        let x = "Hello World".to_string();
+        d = transmute::<&String, &String>(&x);
+    }
+    println!("{}", d);
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
new file mode 100644
index 0000000..f2d600f
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-84660-unsoundness.stderr
@@ -0,0 +1,14 @@
+error: cannot implement trait on type alias impl trait
+  --> $DIR/issue-84660-unsoundness.rs:16:21
+   |
+LL | impl<In, Out> Trait<Bar, In> for Out {
+   |                     ^^^
+   |
+note: type alias impl trait defined here
+  --> $DIR/issue-84660-unsoundness.rs:8:12
+   |
+LL | type Bar = impl Foo;
+   |            ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
index fbab547..ebf3a99 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.rs
@@ -4,11 +4,11 @@
 use std::fmt::Debug;
 
 type FooX = impl Debug;
-//~^ unconstrained opaque type
 
 trait Foo<A> { }
 
 impl Foo<FooX> for () { }
+//~^ cannot implement trait on type alias impl trait
 
 fn foo() -> impl Foo<FooX> {
     ()
diff --git a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
index b1d947a..4a3fb16 100644
--- a/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
+++ b/src/test/ui/type-alias-impl-trait/nested-tait-inference3.stderr
@@ -1,10 +1,14 @@
-error: unconstrained opaque type
+error: cannot implement trait on type alias impl trait
+  --> $DIR/nested-tait-inference3.rs:10:10
+   |
+LL | impl Foo<FooX> for () { }
+   |          ^^^^
+   |
+note: type alias impl trait defined here
   --> $DIR/nested-tait-inference3.rs:6:13
    |
 LL | type FooX = impl Debug;
    |             ^^^^^^^^^^
-   |
-   = note: `FooX` must be used in combination with a concrete type within the same module
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 7e65812..c0b3e95 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -40,10 +40,8 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                         Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
                         None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
                     };
-
                     let lhs_val = lhs_const.int_value(cx, ty)?;
                     let rhs_val = rhs_const.int_value(cx, ty)?;
-
                     let rhs_bound = match range_end {
                         RangeEnd::Included => EndBound::Included(rhs_val),
                         RangeEnd::Excluded => EndBound::Excluded(rhs_val),
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 0d05c83..6ba9ba0 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Lit(ref l) = lit.kind;
-        if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
+        if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
         if cx.typeck_results().expr_ty(exp).is_integral();
 
         then {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 1d6f7ac..be46b79 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -179,7 +179,7 @@ pub fn peel_refs(mut self) -> Self {
 }
 
 /// Parses a `LitKind` to a `Constant`.
-pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
+pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
     match *lit {
         LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
         LitKind::Byte(b) => Constant::Int(u128::from(b)),
@@ -301,7 +301,7 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
                 if is_direct_expn_of(e.span, "cfg").is_some() {
                     None
                 } else {
-                    Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
+                    Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
                 }
             },
             ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
diff --git a/triagebot.toml b/triagebot.toml
index f6f1b91..a5724dd 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -136,6 +136,21 @@
     "T-*",
 ]
 
+[autolabel."T-libs"]
+trigger_files = [
+    "library/alloc",
+    "library/core",
+    "library/panic_abort",
+    "library/panic_unwind",
+    "library/std",
+    "library/stdarch",
+    "library/term",
+    "library/test",
+]
+exclude_labels = [
+    "T-*",
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"