about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs40
-rw-r--r--compiler/rustc_error_messages/locales/en-US/diagnostics.ftl1
-rw-r--r--compiler/rustc_hir/src/definitions.rs5
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs28
-rw-r--r--compiler/rustc_middle/src/query/mod.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs35
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs16
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs10
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs3
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs24
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs2
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs3
-rw-r--r--compiler/rustc_typeck/src/collect.rs4
-rw-r--r--compiler/rustc_typeck/src/errors.rs7
-rw-r--r--library/core/src/char/convert.rs139
-rw-r--r--library/core/src/char/decode.rs49
-rw-r--r--library/core/src/char/mod.rs69
-rw-r--r--library/std/src/sync/mpsc/blocking.rs13
-rw-r--r--library/std/src/sync/mpsc/oneshot.rs24
-rw-r--r--library/std/src/sync/mpsc/shared.rs31
-rw-r--r--library/std/src/sync/mpsc/stream.rs31
-rw-r--r--src/bootstrap/bootstrap.py15
-rw-r--r--src/bootstrap/build.rs19
-rw-r--r--src/bootstrap/builder/tests.rs7
-rw-r--r--src/bootstrap/doc.rs53
-rw-r--r--src/bootstrap/lib.rs5
-rw-r--r--src/bootstrap/metadata.rs6
-rw-r--r--src/bootstrap/test.rs40
-rw-r--r--src/test/mir-opt/derefer_test_multiple.main.Derefer.diff100
-rw-r--r--src/test/mir-opt/derefer_test_multiple.rs9
-rw-r--r--src/test/ui/borrowck/suggest-local-var-for-vector.rs4
-rw-r--r--src/test/ui/borrowck/suggest-local-var-for-vector.stderr24
-rw-r--r--src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs4
-rw-r--r--src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr24
-rw-r--r--src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr22
-rw-r--r--src/test/ui/const-generics/occurs-check/unused-substs-1.stderr3
-rw-r--r--src/test/ui/error-codes/E0516.stderr5
-rw-r--r--src/test/ui/issues/issue-29184.stderr5
-rw-r--r--src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr4
-rw-r--r--src/test/ui/typeof/type_mismatch.stderr5
m---------src/tools/miri16
43 files changed, 492 insertions, 421 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index b945d687043..9e5fb674772 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -785,13 +785,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         issued_borrow: &BorrowData<'tcx>,
         explanation: BorrowExplanation,
     ) {
-        let used_in_call =
-            matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
+        let used_in_call = matches!(
+            explanation,
+            BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _)
+        );
         if !used_in_call {
             debug!("not later used in call");
             return;
         }
 
+        let use_span =
+            if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation {
+                Some(use_span)
+            } else {
+                None
+            };
+
         let outer_call_loc =
             if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
                 loc
@@ -835,7 +844,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
 
         let inner_call_span = inner_call_term.source_info.span;
-        let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
+        let outer_call_span = match use_span {
+            Some(span) => span,
+            None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span,
+        };
         if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
             // FIXME: This stops the suggestion in some cases where it should be emitted.
             //        Fix the spans for those cases so it's emitted correctly.
@@ -845,8 +857,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
             return;
         }
-        err.span_help(inner_call_span, "try adding a local storing this argument...");
-        err.span_help(outer_call_span, "...and then using that local as the argument to this call");
+        err.span_help(
+            inner_call_span,
+            &format!(
+                "try adding a local storing this{}...",
+                if use_span.is_some() { "" } else { " argument" }
+            ),
+        );
+        err.span_help(
+            outer_call_span,
+            &format!(
+                "...and then using that local {}",
+                if use_span.is_some() { "here" } else { "as the argument to this call" }
+            ),
+        );
     }
 
     fn suggest_split_at_mut_if_applicable(
@@ -1912,10 +1936,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         } else {
             "cannot assign twice to immutable variable"
         };
-        if span != assigned_span {
-            if !from_arg {
-                err.span_label(assigned_span, format!("first assignment to {}", place_description));
-            }
+        if span != assigned_span && !from_arg {
+            err.span_label(assigned_span, format!("first assignment to {}", place_description));
         }
         if let Some(decl) = local_decl
             && let Some(name) = local_name
diff --git a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
index 336e7a66857..2b1deb34304 100644
--- a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl
@@ -62,6 +62,7 @@ typeck-functional-record-update-on-non-struct =
 
 typeck-typeof-reserved-keyword-used =
     `typeof` is a reserved keyword but unimplemented
+    .suggestion = consider replacing `typeof(...)` with an actual type
     .label = reserved keyword
 
 typeck-return-stmt-outside-of-fn-body =
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index c62d3b9be2f..4908992085a 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -147,6 +147,11 @@ impl DefKey {
         // DefPathHashes in this DefPathTable.
         DefPathHash::new(parent.stable_crate_id(), local_hash)
     }
+
+    #[inline]
+    pub fn get_opt_name(&self) -> Option<Symbol> {
+        self.disambiguated_data.data.get_opt_name()
+    }
 }
 
 /// A pair of `DefPathData` and an integer disambiguator. The integer is
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 561653f3beb..65796fbc698 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,5 +1,5 @@
 use crate::hir::{ModuleItems, Owner};
-use crate::ty::TyCtxt;
+use crate::ty::{DefIdTree, TyCtxt};
 use rustc_ast as ast;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -545,23 +545,21 @@ impl<'hir> Map<'hir> {
         });
     }
 
-    pub fn ty_param_owner(self, id: HirId) -> LocalDefId {
-        match self.get(id) {
-            Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
-                id.expect_owner()
-            }
-            Node::GenericParam(_) => self.get_parent_item(id),
-            _ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)),
+    pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId {
+        let def_kind = self.tcx.def_kind(def_id);
+        match def_kind {
+            DefKind::Trait | DefKind::TraitAlias => def_id,
+            DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id).unwrap(),
+            _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
 
-    pub fn ty_param_name(self, id: HirId) -> Symbol {
-        match self.get(id) {
-            Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
-                kw::SelfUpper
-            }
-            Node::GenericParam(param) => param.name.ident().name,
-            _ => bug!("ty_param_name: {} not a type parameter", self.node_to_string(id)),
+    pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol {
+        let def_kind = self.tcx.def_kind(def_id);
+        match def_kind {
+            DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper,
+            DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()),
+            _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind),
         }
     }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 89761bf4e27..bbe1d367b77 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -517,10 +517,7 @@ rustc_queries! {
     /// To avoid cycles within the predicates of a single item we compute
     /// per-type-parameter predicates for resolving `T::AssocTy`.
     query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
-        desc { |tcx| "computing the bounds for type parameter `{}`", {
-            let id = tcx.hir().local_def_id_to_hir_id(key.1);
-            tcx.hir().ty_param_name(id)
-        }}
+        desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) }
     }
 
     query trait_def(key: DefId) -> ty::TraitDef {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 399817d59c4..c2accea11ba 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1991,27 +1991,25 @@ impl<'tcx> TyCtxt<'tcx> {
             .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value())
     }
 
-    fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> {
-        self.hir().get_if_local(def_id).and_then(|node| node.ident())
-    }
-
-    fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> {
+    fn opt_item_name(self, def_id: DefId) -> Option<Symbol> {
         if def_id.index == CRATE_DEF_INDEX {
             Some(self.crate_name(def_id.krate))
         } else {
             let def_key = self.def_key(def_id);
             match def_key.disambiguated_data.data {
                 // The name of a constructor is that of its parent.
-                rustc_hir::definitions::DefPathData::Ctor => self.item_name_from_def_id(DefId {
-                    krate: def_id.krate,
-                    index: def_key.parent.unwrap(),
-                }),
-                _ => def_key.disambiguated_data.data.get_opt_name(),
+                rustc_hir::definitions::DefPathData::Ctor => self
+                    .opt_item_name(DefId { krate: def_id.krate, index: def_key.parent.unwrap() }),
+                // The name of opaque types only exists in HIR.
+                rustc_hir::definitions::DefPathData::ImplTrait
+                    if let Some(def_id) = def_id.as_local() =>
+                    self.hir().opt_name(self.hir().local_def_id_to_hir_id(def_id)),
+                _ => def_key.get_opt_name(),
             }
         }
     }
 
-    /// Look up the name of an item across crates. This does not look at HIR.
+    /// Look up the name of a definition across crates. This does not look at HIR.
     ///
     /// When possible, this function should be used for cross-crate lookups over
     /// [`opt_item_name`] to avoid invalidating the incremental cache. If you
@@ -2023,18 +2021,21 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn item_name(self, id: DefId) -> Symbol {
         // Look at cross-crate items first to avoid invalidating the incremental cache
         // unless we have to.
-        self.item_name_from_def_id(id).unwrap_or_else(|| {
+        self.opt_item_name(id).unwrap_or_else(|| {
             bug!("item_name: no name for {:?}", self.def_path(id));
         })
     }
 
-    /// Look up the name and span of an item or [`Node`].
+    /// Look up the name and span of a definition.
     ///
     /// See [`item_name`][Self::item_name] for more information.
-    pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> {
-        // Look at the HIR first so the span will be correct if this is a local item.
-        self.item_name_from_hir(def_id)
-            .or_else(|| self.item_name_from_def_id(def_id).map(Ident::with_dummy_span))
+    pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> {
+        let def = self.opt_item_name(def_id)?;
+        let span = def_id
+            .as_local()
+            .and_then(|id| self.def_ident_span(id))
+            .unwrap_or(rustc_span::DUMMY_SP);
+        Some(Ident::new(def, span))
     }
 
     pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> {
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 79aac163550..24b626ad966 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -11,6 +11,8 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         for (i, stmt) in data.statements.iter_mut().enumerate() {
             match stmt.kind {
                 StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => {
+                    let mut place_local = place.local;
+                    let mut last_len = 0;
                     for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() {
                         if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() {
                             // The type that we are derefing.
@@ -23,15 +25,18 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             patch.add_statement(loc, StatementKind::StorageLive(temp));
 
                             // We are adding current p_ref's projections to our
-                            // temp value.
-                            let deref_place =
-                                Place::from(p_ref.local).project_deeper(p_ref.projection, tcx);
+                            // temp value, excluding projections we already covered.
+                            let deref_place = Place::from(place_local)
+                                .project_deeper(&p_ref.projection[last_len..], tcx);
                             patch.add_assign(
                                 loc,
                                 Place::from(temp),
                                 Rvalue::Use(Operand::Move(deref_place)),
                             );
 
+                            place_local = temp;
+                            last_len = p_ref.projection.len();
+
                             // We are creating a place by using our temp value's location
                             // and copying derefed values which we need to create new statement.
                             let temp_place =
@@ -50,11 +55,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                             // Since our job with the temp is done it should be gone
                             let loc = Location { block: block, statement_index: i + 1 };
                             patch.add_statement(loc, StatementKind::StorageDead(temp));
-
-                            // As all projections are off the base projection, if there are
-                            // multiple derefs in the middle of projection, it might cause
-                            // unsoundness, to not let that happen we break the loop.
-                            break;
                         }
                     }
                 }
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 489d513c104..cf13c856a71 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -201,7 +201,7 @@ fn emit_unused_generic_params_error<'tcx>(
         return;
     }
 
-    let fn_span = match tcx.opt_item_name(def_id) {
+    let fn_span = match tcx.opt_item_ident(def_id) {
         Some(ident) => ident.span,
         _ => tcx.def_span(def_id),
     };
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 7c3f306717a..c920c80d1bb 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2064,7 +2064,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::BindingObligation(item_def_id, span) => {
                 let item_name = tcx.def_path_str(item_def_id);
                 let mut multispan = MultiSpan::from(span);
-                if let Some(ident) = tcx.opt_item_name(item_def_id) {
+                if let Some(ident) = tcx.opt_item_ident(item_def_id) {
                     let sm = tcx.sess.source_map();
                     let same_line =
                         match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) {
@@ -2267,7 +2267,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if !is_upvar_tys_infer_tuple {
                     let msg = format!("required because it appears within the type `{}`", ty);
                     match ty.kind() {
-                        ty::Adt(def, _) => match self.tcx.opt_item_name(def.did()) {
+                        ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
                             Some(ident) => err.span_note(ident.span, &msg),
                             None => err.note(&msg),
                         },
@@ -2475,7 +2475,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 );
                 let sp = self
                     .tcx
-                    .opt_item_name(trait_item_def_id)
+                    .opt_item_ident(trait_item_def_id)
                     .map(|i| i.span)
                     .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id));
                 let mut assoc_span: MultiSpan = sp.into();
@@ -2486,7 +2486,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let Some(ident) = self
                     .tcx
                     .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_name(i.container.id()))
+                    .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
                 {
                     assoc_span.push_span_label(ident.span, "in this trait");
                 }
@@ -2511,7 +2511,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 if let Some(ident) = self
                     .tcx
                     .opt_associated_item(trait_item_def_id)
-                    .and_then(|i| self.tcx.opt_item_name(i.container.id()))
+                    .and_then(|i| self.tcx.opt_item_ident(i.container.id()))
                 {
                     assoc_span.push_span_label(ident.span, "in this trait");
                 }
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index a50301dbc87..5f5b81b8924 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -82,8 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 }
                 Res::Def(DefKind::TyParam, src_def_id) => {
                     if let Some(param_local_id) = param.def_id.as_local() {
-                        let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id);
-                        let param_name = tcx.hir().ty_param_name(param_hir_id);
+                        let param_name = tcx.hir().ty_param_name(param_local_id);
                         let param_type = tcx.infer_ctxt().enter(|infcx| {
                             infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id))
                         });
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index b6287031665..6bae0f2eac9 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -1620,8 +1620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         debug!("find_bound_for_assoc_item: predicates={:#?}", predicates);
 
-        let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id);
-        let param_name = tcx.hir().ty_param_name(param_hir_id);
+        let param_name = tcx.hir().ty_param_name(ty_param_def_id);
         self.one_bound_for_assoc_type(
             || {
                 traits::transitive_bounds_that_define_assoc_type(
@@ -2265,12 +2264,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments);
 
-                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 def_id = def_id.expect_local();
+                let item_def_id = tcx.hir().ty_param_owner(def_id);
                 let generics = tcx.generics_of(item_def_id);
-                let index = generics.param_def_id_to_index[&def_id];
-                tcx.mk_ty_param(index, tcx.hir().name(hir_id))
+                let index = generics.param_def_id_to_index[&def_id.to_def_id()];
+                tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id))
             }
             Res::SelfTy { trait_: Some(_), alias_to: None } => {
                 // `Self` in trait or type alias.
@@ -2462,8 +2460,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 self.normalize_ty(ast_ty.span, array_ty)
             }
             hir::TyKind::Typeof(ref e) => {
-                tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span });
-                tcx.type_of(tcx.hir().local_def_id(e.hir_id))
+                let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id));
+                let span = ast_ty.span;
+                tcx.sess.emit_err(TypeofReservedKeywordUsed {
+                    span,
+                    ty,
+                    opt_sugg: Some((span, Applicability::MachineApplicable))
+                        .filter(|_| ty.is_suggestable()),
+                });
+
+                ty
             }
             hir::TyKind::Infer => {
                 // Infer also appears as the type of arguments or return
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 6091b8fee00..e73b9c979eb 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -1012,7 +1012,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     err.help(msg);
                 }
                 err.help(
-                    "if you can't comply with strict provenance and need to expose the pointer\
+                    "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
                 );
 
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 82641a489f6..669521bc472 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -2195,7 +2195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             None => return,
         };
         let param_span = self.tcx.hir().span(param_hir_id);
-        let param_name = self.tcx.hir().ty_param_name(param_hir_id);
+        let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local());
 
         err.span_label(param_span, &format!("type parameter '{}' declared here", param_name));
     }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 55a5eb966c2..77cba1c22c4 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -184,8 +184,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
         _: Ident,
     ) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        let item_def_id = tcx.hir().ty_param_owner(hir_id);
+        let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local());
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id];
         ty::GenericPredicates {
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index ec783a16ef7..026151ce7df 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -558,10 +558,10 @@ fn type_param_predicates(
     // `where T: Foo`.
 
     let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let param_owner = tcx.hir().ty_param_owner(param_id);
+    let param_owner = tcx.hir().ty_param_owner(def_id);
     let generics = tcx.generics_of(param_owner);
     let index = generics.param_def_id_to_index[&def_id.to_def_id()];
-    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(param_id));
+    let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id));
 
     // Don't look for bounds where the type parameter isn't in scope.
     let parent = if item_def_id == param_owner.to_def_id() {
diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs
index 0b78aea9f05..1088be5f566 100644
--- a/compiler/rustc_typeck/src/errors.rs
+++ b/compiler/rustc_typeck/src/errors.rs
@@ -1,5 +1,7 @@
 //! Errors emitted by typeck.
+use rustc_errors::Applicability;
 use rustc_macros::SessionDiagnostic;
+use rustc_middle::ty::Ty;
 use rustc_span::{symbol::Ident, Span, Symbol};
 
 #[derive(SessionDiagnostic)]
@@ -127,10 +129,13 @@ pub struct FunctionalRecordUpdateOnNonStruct {
 
 #[derive(SessionDiagnostic)]
 #[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")]
-pub struct TypeofReservedKeywordUsed {
+pub struct TypeofReservedKeywordUsed<'tcx> {
+    pub ty: Ty<'tcx>,
     #[primary_span]
     #[label]
     pub span: Span,
+    #[suggestion_verbose(message = "suggestion", code = "{ty}")]
+    pub opt_sugg: Option<(Span, Applicability)>,
 }
 
 #[derive(SessionDiagnostic)]
diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs
index 4ee0310b361..778f06aeb63 100644
--- a/library/core/src/char/convert.rs
+++ b/library/core/src/char/convert.rs
@@ -6,52 +6,10 @@ use crate::fmt;
 use crate::mem::transmute;
 use crate::str::FromStr;
 
-/// Converts a `u32` to a `char`.
-///
-/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
-/// `as`:
-///
-/// ```
-/// let c = '💯';
-/// let i = c as u32;
-///
-/// assert_eq!(128175, i);
-/// ```
-///
-/// However, the reverse is not true: not all valid [`u32`]s are valid
-/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value
-/// for a [`char`].
-///
-/// For an unsafe version of this function which ignores these checks, see
-/// [`from_u32_unchecked`].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_u32(0x2764);
-///
-/// assert_eq!(Some('❤'), c);
-/// ```
-///
-/// Returning `None` when the input is not a valid [`char`]:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_u32(0x110000);
-///
-/// assert_eq!(None, c);
-/// ```
-#[doc(alias = "chr")]
+/// Converts a `u32` to a `char`. See [`char::from_u32`].
 #[must_use]
 #[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const fn from_u32(i: u32) -> Option<char> {
+pub(super) const fn from_u32(i: u32) -> Option<char> {
     // FIXME: once Result::ok is const fn, use it here
     match char_try_from_u32(i) {
         Ok(c) => Some(c),
@@ -59,44 +17,11 @@ pub const fn from_u32(i: u32) -> Option<char> {
     }
 }
 
-/// Converts a `u32` to a `char`, ignoring validity.
-///
-/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
-/// `as`:
-///
-/// ```
-/// let c = '💯';
-/// let i = c as u32;
-///
-/// assert_eq!(128175, i);
-/// ```
-///
-/// However, the reverse is not true: not all valid [`u32`]s are valid
-/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to
-/// [`char`], possibly creating an invalid one.
-///
-/// # Safety
-///
-/// This function is unsafe, as it may construct invalid `char` values.
-///
-/// For a safe version of this function, see the [`from_u32`] function.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = unsafe { char::from_u32_unchecked(0x2764) };
-///
-/// assert_eq!('❤', c);
-/// ```
+/// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`].
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
 #[inline]
 #[must_use]
-#[stable(feature = "char_from_unchecked", since = "1.5.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const unsafe fn from_u32_unchecked(i: u32) -> char {
+pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char {
     // SAFETY: the caller must guarantee that `i` is a valid char value.
     if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } }
 }
@@ -317,60 +242,10 @@ impl fmt::Display for CharTryFromError {
     }
 }
 
-/// Converts a digit in the given radix to a `char`.
-///
-/// A 'radix' here is sometimes also called a 'base'. A radix of two
-/// indicates a binary number, a radix of ten, decimal, and a radix of
-/// sixteen, hexadecimal, to give some common values. Arbitrary
-/// radices are supported.
-///
-/// `from_digit()` will return `None` if the input is not a digit in
-/// the given radix.
-///
-/// # Panics
-///
-/// Panics if given a radix larger than 36.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_digit(4, 10);
-///
-/// assert_eq!(Some('4'), c);
-///
-/// // Decimal 11 is a single digit in base 16
-/// let c = char::from_digit(11, 16);
-///
-/// assert_eq!(Some('b'), c);
-/// ```
-///
-/// Returning `None` when the input is not a digit:
-///
-/// ```
-/// use std::char;
-///
-/// let c = char::from_digit(20, 10);
-///
-/// assert_eq!(None, c);
-/// ```
-///
-/// Passing a large radix, causing a panic:
-///
-/// ```should_panic
-/// use std::char;
-///
-/// // this panics
-/// let c = char::from_digit(1, 37);
-/// ```
+/// Converts a digit in the given radix to a `char`. See [`char::from_digit`].
 #[inline]
 #[must_use]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
-pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
+pub(super) const fn from_digit(num: u32, radix: u32) -> Option<char> {
     if radix > 36 {
         panic!("from_digit: radix is too high (maximum 36)");
     }
diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs
index 794c9c13cc3..71297acd171 100644
--- a/library/core/src/char/decode.rs
+++ b/library/core/src/char/decode.rs
@@ -30,54 +30,9 @@ pub struct DecodeUtf16Error {
 }
 
 /// Creates an iterator over the UTF-16 encoded code points in `iter`,
-/// returning unpaired surrogates as `Err`s.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// use std::char::decode_utf16;
-///
-/// // 𝄞mus<invalid>ic<invalid>
-/// let v = [
-///     0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
-/// ];
-///
-/// assert_eq!(
-///     decode_utf16(v.iter().cloned())
-///         .map(|r| r.map_err(|e| e.unpaired_surrogate()))
-///         .collect::<Vec<_>>(),
-///     vec![
-///         Ok('𝄞'),
-///         Ok('m'), Ok('u'), Ok('s'),
-///         Err(0xDD1E),
-///         Ok('i'), Ok('c'),
-///         Err(0xD834)
-///     ]
-/// );
-/// ```
-///
-/// A lossy decoder can be obtained by replacing `Err` results with the replacement character:
-///
-/// ```
-/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER};
-///
-/// // 𝄞mus<invalid>ic<invalid>
-/// let v = [
-///     0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834,
-/// ];
-///
-/// assert_eq!(
-///     decode_utf16(v.iter().cloned())
-///        .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-///        .collect::<String>(),
-///     "𝄞mus�ic�"
-/// );
-/// ```
-#[stable(feature = "decode_utf16", since = "1.9.0")]
+/// returning unpaired surrogates as `Err`s. See [`char::decode_utf16`].
 #[inline]
-pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
+pub(super) fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
     DecodeUtf16 { iter: iter.into_iter(), buf: None }
 }
 
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index 9364ac4f3ec..0df23e7bbe6 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -23,18 +23,12 @@ mod decode;
 mod methods;
 
 // stable re-exports
-#[stable(feature = "char_from_unchecked", since = "1.5.0")]
-pub use self::convert::from_u32_unchecked;
 #[stable(feature = "try_from", since = "1.34.0")]
 pub use self::convert::CharTryFromError;
 #[stable(feature = "char_from_str", since = "1.20.0")]
 pub use self::convert::ParseCharError;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::convert::{from_digit, from_u32};
 #[stable(feature = "decode_utf16", since = "1.9.0")]
-pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error};
-#[stable(feature = "unicode_version", since = "1.45.0")]
-pub use crate::unicode::UNICODE_VERSION;
+pub use self::decode::{DecodeUtf16, DecodeUtf16Error};
 
 // perma-unstable re-exports
 #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")]
@@ -89,30 +83,57 @@ const MAX_THREE_B: u32 = 0x10000;
     Cn  Unassigned              a reserved unassigned code point or a noncharacter
 */
 
-/// The highest valid code point a `char` can have, `'\u{10FFFF}'`.
-///
-/// # Examples
-///
-/// ```
-/// # fn something_which_returns_char() -> char { 'a' }
-/// let c: char = something_which_returns_char();
-/// assert!(c <= char::MAX);
-///
-/// let value_at_max = char::MAX as u32;
-/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}'));
-/// assert_eq!(char::from_u32(value_at_max + 1), None);
-/// ```
+/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub const MAX: char = char::MAX;
 
 /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a
-/// decoding error.
-///
-/// It can occur, for example, when giving ill-formed UTF-8 bytes to
-/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy).
+/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead.
 #[stable(feature = "decode_utf16", since = "1.9.0")]
 pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER;
 
+/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of
+/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead.
+#[stable(feature = "unicode_version", since = "1.45.0")]
+pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION;
+
+/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning
+/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead.
+#[stable(feature = "decode_utf16", since = "1.9.0")]
+#[inline]
+pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> {
+    self::decode::decode_utf16(iter)
+}
+
+/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const fn from_u32(i: u32) -> Option<char> {
+    self::convert::from_u32(i)
+}
+
+/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`].
+/// instead.
+#[stable(feature = "char_from_unchecked", since = "1.5.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const unsafe fn from_u32_unchecked(i: u32) -> char {
+    // SAFETY: the safety contract must be upheld by the caller.
+    unsafe { self::convert::from_u32_unchecked(i) }
+}
+
+/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead.
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")]
+#[must_use]
+#[inline]
+pub const fn from_digit(num: u32, radix: u32) -> Option<char> {
+    self::convert::from_digit(num, radix)
+}
+
 /// Returns an iterator that yields the hexadecimal Unicode escape of a
 /// character, as `char`s.
 ///
diff --git a/library/std/src/sync/mpsc/blocking.rs b/library/std/src/sync/mpsc/blocking.rs
index 4c852b8ee81..021df7b096c 100644
--- a/library/std/src/sync/mpsc/blocking.rs
+++ b/library/std/src/sync/mpsc/blocking.rs
@@ -1,6 +1,5 @@
 //! Generic support for building blocking abstractions.
 
-use crate::mem;
 use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::Arc;
 use crate::thread::{self, Thread};
@@ -47,18 +46,18 @@ impl SignalToken {
         wake
     }
 
-    /// Converts to an unsafe usize value. Useful for storing in a pipe's state
+    /// Converts to an unsafe raw pointer. Useful for storing in a pipe's state
     /// flag.
     #[inline]
-    pub unsafe fn cast_to_usize(self) -> usize {
-        mem::transmute(self.inner)
+    pub unsafe fn to_raw(self) -> *mut u8 {
+        Arc::into_raw(self.inner) as *mut u8
     }
 
-    /// Converts from an unsafe usize value. Useful for retrieving a pipe's state
+    /// Converts from an unsafe raw pointer. Useful for retrieving a pipe's state
     /// flag.
     #[inline]
-    pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken {
-        SignalToken { inner: mem::transmute(signal_ptr) }
+    pub unsafe fn from_raw(signal_ptr: *mut u8) -> SignalToken {
+        SignalToken { inner: Arc::from_raw(signal_ptr as *mut Inner) }
     }
 }
 
diff --git a/library/std/src/sync/mpsc/oneshot.rs b/library/std/src/sync/mpsc/oneshot.rs
index 3dcf03f579a..0e259b8aecb 100644
--- a/library/std/src/sync/mpsc/oneshot.rs
+++ b/library/std/src/sync/mpsc/oneshot.rs
@@ -27,15 +27,15 @@ pub use self::UpgradeResult::*;
 
 use crate::cell::UnsafeCell;
 use crate::ptr;
-use crate::sync::atomic::{AtomicUsize, Ordering};
+use crate::sync::atomic::{AtomicPtr, Ordering};
 use crate::sync::mpsc::blocking::{self, SignalToken};
 use crate::sync::mpsc::Receiver;
 use crate::time::Instant;
 
 // Various states you can find a port in.
-const EMPTY: usize = 0; // initial state: no data, no blocked receiver
-const DATA: usize = 1; // data ready for receiver to take
-const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded
+const EMPTY: *mut u8 = ptr::invalid_mut::<u8>(0); // initial state: no data, no blocked receiver
+const DATA: *mut u8 = ptr::invalid_mut::<u8>(1); // data ready for receiver to take
+const DISCONNECTED: *mut u8 = ptr::invalid_mut::<u8>(2); // channel is disconnected OR upgraded
 // Any other value represents a pointer to a SignalToken value. The
 // protocol ensures that when the state moves *to* a pointer,
 // ownership of the token is given to the packet, and when the state
@@ -44,7 +44,7 @@ const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded
 
 pub struct Packet<T> {
     // Internal state of the chan/port pair (stores the blocked thread as well)
-    state: AtomicUsize,
+    state: AtomicPtr<u8>,
     // One-shot data slot location
     data: UnsafeCell<Option<T>>,
     // when used for the second time, a oneshot channel must be upgraded, and
@@ -75,7 +75,7 @@ impl<T> Packet<T> {
         Packet {
             data: UnsafeCell::new(None),
             upgrade: UnsafeCell::new(NothingSent),
-            state: AtomicUsize::new(EMPTY),
+            state: AtomicPtr::new(EMPTY),
         }
     }
 
@@ -108,7 +108,7 @@ impl<T> Packet<T> {
                 // There is a thread waiting on the other end. We leave the 'DATA'
                 // state inside so it'll pick it up on the other end.
                 ptr => {
-                    SignalToken::cast_from_usize(ptr).signal();
+                    SignalToken::from_raw(ptr).signal();
                     Ok(())
                 }
             }
@@ -126,7 +126,7 @@ impl<T> Packet<T> {
         // like we're not empty, then immediately go through to `try_recv`.
         if self.state.load(Ordering::SeqCst) == EMPTY {
             let (wait_token, signal_token) = blocking::tokens();
-            let ptr = unsafe { signal_token.cast_to_usize() };
+            let ptr = unsafe { signal_token.to_raw() };
 
             // race with senders to enter the blocking state
             if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() {
@@ -142,7 +142,7 @@ impl<T> Packet<T> {
                 }
             } else {
                 // drop the signal token, since we never blocked
-                drop(unsafe { SignalToken::cast_from_usize(ptr) });
+                drop(unsafe { SignalToken::from_raw(ptr) });
             }
         }
 
@@ -218,7 +218,7 @@ impl<T> Packet<T> {
                 }
 
                 // If someone's waiting, we gotta wake them up
-                ptr => UpWoke(SignalToken::cast_from_usize(ptr)),
+                ptr => UpWoke(SignalToken::from_raw(ptr)),
             }
         }
     }
@@ -229,7 +229,7 @@ impl<T> Packet<T> {
 
             // If someone's waiting, we gotta wake them up
             ptr => unsafe {
-                SignalToken::cast_from_usize(ptr).signal();
+                SignalToken::from_raw(ptr).signal();
             },
         }
     }
@@ -301,7 +301,7 @@ impl<T> Packet<T> {
 
             // We woke ourselves up from select.
             ptr => unsafe {
-                drop(SignalToken::cast_from_usize(ptr));
+                drop(SignalToken::from_raw(ptr));
                 Ok(false)
             },
         }
diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs
index 56162655544..51917bd96bd 100644
--- a/library/std/src/sync/mpsc/shared.rs
+++ b/library/std/src/sync/mpsc/shared.rs
@@ -15,7 +15,7 @@ use core::intrinsics::abort;
 
 use crate::cell::UnsafeCell;
 use crate::ptr;
-use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
+use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, Ordering};
 use crate::sync::mpsc::blocking::{self, SignalToken};
 use crate::sync::mpsc::mpsc_queue as mpsc;
 use crate::sync::{Mutex, MutexGuard};
@@ -29,12 +29,13 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 const MAX_STEALS: isize = 5;
 #[cfg(not(test))]
 const MAX_STEALS: isize = 1 << 20;
+const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver
 
 pub struct Packet<T> {
     queue: mpsc::Queue<T>,
     cnt: AtomicIsize,          // How many items are on this channel
     steals: UnsafeCell<isize>, // How many times has a port received without blocking?
-    to_wake: AtomicUsize,      // SignalToken for wake up
+    to_wake: AtomicPtr<u8>,    // SignalToken for wake up
 
     // The number of channels which are currently using this packet.
     channels: AtomicUsize,
@@ -68,7 +69,7 @@ impl<T> Packet<T> {
             queue: mpsc::Queue::new(),
             cnt: AtomicIsize::new(0),
             steals: UnsafeCell::new(0),
-            to_wake: AtomicUsize::new(0),
+            to_wake: AtomicPtr::new(EMPTY),
             channels: AtomicUsize::new(2),
             port_dropped: AtomicBool::new(false),
             sender_drain: AtomicIsize::new(0),
@@ -93,8 +94,8 @@ impl<T> Packet<T> {
     pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) {
         if let Some(token) = token {
             assert_eq!(self.cnt.load(Ordering::SeqCst), 0);
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
-            self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst);
+            assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
+            self.to_wake.store(unsafe { token.to_raw() }, Ordering::SeqCst);
             self.cnt.store(-1, Ordering::SeqCst);
 
             // This store is a little sketchy. What's happening here is that
@@ -250,10 +251,10 @@ impl<T> Packet<T> {
         unsafe {
             assert_eq!(
                 self.to_wake.load(Ordering::SeqCst),
-                0,
+                EMPTY,
                 "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364"
             );
-            let ptr = token.cast_to_usize();
+            let ptr = token.to_raw();
             self.to_wake.store(ptr, Ordering::SeqCst);
 
             let steals = ptr::replace(self.steals.get(), 0);
@@ -272,8 +273,8 @@ impl<T> Packet<T> {
                 }
             }
 
-            self.to_wake.store(0, Ordering::SeqCst);
-            drop(SignalToken::cast_from_usize(ptr));
+            self.to_wake.store(EMPTY, Ordering::SeqCst);
+            drop(SignalToken::from_raw(ptr));
             Abort
         }
     }
@@ -415,9 +416,9 @@ impl<T> Packet<T> {
     // Consumes ownership of the 'to_wake' field.
     fn take_to_wake(&self) -> SignalToken {
         let ptr = self.to_wake.load(Ordering::SeqCst);
-        self.to_wake.store(0, Ordering::SeqCst);
-        assert!(ptr != 0);
-        unsafe { SignalToken::cast_from_usize(ptr) }
+        self.to_wake.store(EMPTY, Ordering::SeqCst);
+        assert!(ptr != EMPTY);
+        unsafe { SignalToken::from_raw(ptr) }
     }
 
     ////////////////////////////////////////////////////////////////////////////
@@ -462,7 +463,7 @@ impl<T> Packet<T> {
         let prev = self.bump(steals + 1);
 
         if prev == DISCONNECTED {
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
             true
         } else {
             let cur = prev + steals + 1;
@@ -470,7 +471,7 @@ impl<T> Packet<T> {
             if prev < 0 {
                 drop(self.take_to_wake());
             } else {
-                while self.to_wake.load(Ordering::SeqCst) != 0 {
+                while self.to_wake.load(Ordering::SeqCst) != EMPTY {
                     thread::yield_now();
                 }
             }
@@ -494,7 +495,7 @@ impl<T> Drop for Packet<T> {
         // `to_wake`, so this assert cannot be removed with also removing
         // the `to_wake` assert.
         assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY);
         assert_eq!(self.channels.load(Ordering::SeqCst), 0);
     }
 }
diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs
index 2a1d3f8967e..4c3812c79f6 100644
--- a/library/std/src/sync/mpsc/stream.rs
+++ b/library/std/src/sync/mpsc/stream.rs
@@ -17,7 +17,7 @@ use crate::ptr;
 use crate::thread;
 use crate::time::Instant;
 
-use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering};
+use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, Ordering};
 use crate::sync::mpsc::blocking::{self, SignalToken};
 use crate::sync::mpsc::spsc_queue as spsc;
 use crate::sync::mpsc::Receiver;
@@ -27,6 +27,7 @@ const DISCONNECTED: isize = isize::MIN;
 const MAX_STEALS: isize = 5;
 #[cfg(not(test))]
 const MAX_STEALS: isize = 1 << 20;
+const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver
 
 pub struct Packet<T> {
     // internal queue for all messages
@@ -34,8 +35,8 @@ pub struct Packet<T> {
 }
 
 struct ProducerAddition {
-    cnt: AtomicIsize,     // How many items are on this channel
-    to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
+    cnt: AtomicIsize,       // How many items are on this channel
+    to_wake: AtomicPtr<u8>, // SignalToken for the blocked thread to wake up
 
     port_dropped: AtomicBool, // flag if the channel has been destroyed.
 }
@@ -71,7 +72,7 @@ impl<T> Packet<T> {
                     128,
                     ProducerAddition {
                         cnt: AtomicIsize::new(0),
-                        to_wake: AtomicUsize::new(0),
+                        to_wake: AtomicPtr::new(EMPTY),
 
                         port_dropped: AtomicBool::new(false),
                     },
@@ -147,17 +148,17 @@ impl<T> Packet<T> {
     // Consumes ownership of the 'to_wake' field.
     fn take_to_wake(&self) -> SignalToken {
         let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
-        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
-        assert!(ptr != 0);
-        unsafe { SignalToken::cast_from_usize(ptr) }
+        self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst);
+        assert!(ptr != EMPTY);
+        unsafe { SignalToken::from_raw(ptr) }
     }
 
     // Decrements the count on the channel for a sleeper, returning the sleeper
     // back if it shouldn't sleep. Note that this is the location where we take
     // steals into account.
     fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
-        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
-        let ptr = unsafe { token.cast_to_usize() };
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
+        let ptr = unsafe { token.to_raw() };
         self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
 
         let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
@@ -176,8 +177,8 @@ impl<T> Packet<T> {
             }
         }
 
-        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
-        Err(unsafe { SignalToken::cast_from_usize(ptr) })
+        self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst);
+        Err(unsafe { SignalToken::from_raw(ptr) })
     }
 
     pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> {
@@ -376,7 +377,7 @@ impl<T> Packet<T> {
         // of time until the data is actually sent.
         if was_upgrade {
             assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
-            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
             return Ok(true);
         }
 
@@ -389,7 +390,7 @@ impl<T> Packet<T> {
         // If we were previously disconnected, then we know for sure that there
         // is no thread in to_wake, so just keep going
         let has_data = if prev == DISCONNECTED {
-            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
             true // there is data, that data is that we're disconnected
         } else {
             let cur = prev + steals + 1;
@@ -412,7 +413,7 @@ impl<T> Packet<T> {
             if prev < 0 {
                 drop(self.take_to_wake());
             } else {
-                while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 {
+                while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != EMPTY {
                     thread::yield_now();
                 }
             }
@@ -451,6 +452,6 @@ impl<T> Drop for Packet<T> {
         // `to_wake`, so this assert cannot be removed with also removing
         // the `to_wake` assert.
         assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY);
     }
 }
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 0b6bdf47419..00dc7da275a 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1097,8 +1097,19 @@ class RustBuild(object):
 
     def update_submodules(self):
         """Update submodules"""
-        if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \
-                self.get_toml('submodules') == "false":
+        has_git = os.path.exists(os.path.join(self.rust_root, ".git"))
+        # This just arbitrarily checks for cargo, but any workspace member in
+        # a submodule would work.
+        has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml"))
+        if not has_git and not has_submodules:
+            print("This is not a git repository, and the requisite git submodules were not found.")
+            print("If you downloaded the source from https://github.com/rust-lang/rust/releases,")
+            print("those sources will not work. Instead, consider downloading from the source")
+            print("releases linked at")
+            print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code")
+            print("or clone the repository at https://github.com/rust-lang/rust/.")
+            raise SystemExit(1)
+        if not has_git or self.get_toml('submodules') == "false":
             return
 
         default_encoding = sys.getdefaultencoding()
diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs
index 8a5bf933d56..ab34d5c1e55 100644
--- a/src/bootstrap/build.rs
+++ b/src/bootstrap/build.rs
@@ -1,10 +1,25 @@
+use env::consts::{EXE_EXTENSION, EXE_SUFFIX};
 use std::env;
+use std::ffi::OsString;
 use std::path::PathBuf;
 
+/// Given an executable called `name`, return the filename for the
+/// executable for a particular target.
+pub fn exe(name: &PathBuf) -> PathBuf {
+    if EXE_EXTENSION != "" && name.extension() != Some(EXE_EXTENSION.as_ref()) {
+        let mut name: OsString = name.clone().into();
+        name.push(EXE_SUFFIX);
+        name.into()
+    } else {
+        name.clone()
+    }
+}
+
 fn main() {
+    let host = env::var("HOST").unwrap();
     println!("cargo:rerun-if-changed=build.rs");
     println!("cargo:rerun-if-env-changed=RUSTC");
-    println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap());
+    println!("cargo:rustc-env=BUILD_TRIPLE={}", host);
 
     // This may not be a canonicalized path.
     let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
@@ -12,7 +27,7 @@ fn main() {
     if rustc.is_relative() {
         println!("cargo:rerun-if-env-changed=PATH");
         for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
-            let absolute = dir.join(&rustc);
+            let absolute = dir.join(&exe(&rustc));
             if absolute.exists() {
                 rustc = absolute;
                 break;
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index b76bb569852..a59f72ed968 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -8,12 +8,9 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
     config.save_toolstates = None;
     config.dry_run = true;
     config.ninja_in_file = false;
-    config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap());
-    config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap());
-    config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap());
     // try to avoid spurious failures in dist where we create/delete each others file
-    let dir = config
-        .out
+    // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us
+    let dir = Path::new(env!("OUT_DIR"))
         .join("tmp-rustbuild-tests")
         .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
     t!(fs::create_dir_all(&dir));
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 5f16716a0fd..077a86af50b 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -7,7 +7,6 @@
 //! Everything here is basically just a shim around calling either `rustbook` or
 //! `rustdoc`.
 
-use std::collections::HashSet;
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
@@ -554,13 +553,9 @@ impl Step for Rustc {
         let paths = builder
             .paths
             .iter()
-            .map(components_simplified)
-            .filter_map(|path| {
-                if path.get(0) == Some(&"compiler") {
-                    path.get(1).map(|p| p.to_owned())
-                } else {
-                    None
-                }
+            .filter(|path| {
+                let components = components_simplified(path);
+                components.len() >= 2 && components[0] == "compiler"
             })
             .collect::<Vec<_>>();
 
@@ -608,38 +603,22 @@ impl Step for Rustc {
         cargo.rustdocflag("--extern-html-root-url");
         cargo.rustdocflag("ena=https://docs.rs/ena/latest/");
 
-        let mut compiler_crates = HashSet::new();
-
-        if paths.is_empty() {
-            // Find dependencies for top level crates.
-            for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] {
-                compiler_crates.extend(
-                    builder
-                        .in_tree_crates(root_crate, Some(target))
-                        .into_iter()
-                        .map(|krate| krate.name),
-                );
-            }
+        let root_crates = if paths.is_empty() {
+            vec![
+                INTERNER.intern_str("rustc_driver"),
+                INTERNER.intern_str("rustc_codegen_llvm"),
+                INTERNER.intern_str("rustc_codegen_ssa"),
+            ]
         } else {
-            for root_crate in paths {
-                if !builder.src.join("compiler").join(&root_crate).exists() {
-                    builder.info(&format!(
-                        "\tskipping - compiler/{} (unknown compiler crate)",
-                        root_crate
-                    ));
-                } else {
-                    compiler_crates.extend(
-                        builder
-                            .in_tree_crates(root_crate, Some(target))
-                            .into_iter()
-                            .map(|krate| krate.name),
-                    );
-                }
-            }
-        }
+            paths.into_iter().map(|p| builder.crate_paths[p]).collect()
+        };
+        // Find dependencies for top level crates.
+        let compiler_crates = root_crates.iter().flat_map(|krate| {
+            builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name)
+        });
 
         let mut to_open = None;
-        for krate in &compiler_crates {
+        for krate in compiler_crates {
             // Create all crate output directories first to make sure rustdoc uses
             // relative links.
             // FIXME: Cargo should probably do this itself.
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 570a61742bc..e4937d7bbcc 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -302,7 +302,9 @@ pub struct Build {
     ar: HashMap<TargetSelection, PathBuf>,
     ranlib: HashMap<TargetSelection, PathBuf>,
     // Miscellaneous
+    // allow bidirectional lookups: both name -> path and path -> name
     crates: HashMap<Interned<String>, Crate>,
+    crate_paths: HashMap<PathBuf, Interned<String>>,
     is_sudo: bool,
     ci_env: CiEnv,
     delayed_failures: RefCell<Vec<String>>,
@@ -452,7 +454,7 @@ impl Build {
                 .map(PathBuf::from)
                 .unwrap_or_else(|_| src.join("target"));
             let bootstrap_out = workspace_target_dir.join("debug");
-            if !bootstrap_out.join("rustc").exists() {
+            if !bootstrap_out.join("rustc").exists() && !cfg!(test) {
                 // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
                 panic!("run `cargo build --bins` before `cargo run`")
             }
@@ -492,6 +494,7 @@ impl Build {
             ar: HashMap::new(),
             ranlib: HashMap::new(),
             crates: HashMap::new(),
+            crate_paths: HashMap::new(),
             is_sudo,
             ci_env: CiEnv::current(),
             delayed_failures: RefCell::new(Vec::new()),
diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs
index 59dc50be47f..e193e70a0c4 100644
--- a/src/bootstrap/metadata.rs
+++ b/src/bootstrap/metadata.rs
@@ -49,7 +49,11 @@ pub fn build(build: &mut Build) {
                 .filter(|dep| dep.source.is_none())
                 .map(|dep| INTERNER.intern_string(dep.name))
                 .collect();
-            build.crates.insert(name, Crate { name, deps, path });
+            let krate = Crate { name, deps, path };
+            let relative_path = krate.local_path(build);
+            build.crates.insert(name, krate);
+            let existing_path = build.crate_paths.insert(relative_path, name);
+            assert!(existing_path.is_none(), "multiple crates with the same path");
         }
     }
 }
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index 81200ba60b0..b88684791bc 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -21,7 +21,6 @@ use crate::native;
 use crate::tool::{self, SourceType, Tool};
 use crate::toolstate::ToolState;
 use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t};
-use crate::Crate as CargoCrate;
 use crate::{envify, CLang, DocTests, GitRepo, Mode};
 
 const ADB_TEST_DIR: &str = "/data/tmp/work";
@@ -1901,19 +1900,10 @@ impl Step for CrateLibrustc {
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
         let compiler = builder.compiler(builder.top_stage, run.build_triple());
+        let krate = builder.crate_paths[&run.path];
+        let test_kind = builder.kind.into();
 
-        for krate in builder.in_tree_crates("rustc-main", Some(run.target)) {
-            if krate.path.ends_with(&run.path) {
-                let test_kind = builder.kind.into();
-
-                builder.ensure(CrateLibrustc {
-                    compiler,
-                    target: run.target,
-                    test_kind,
-                    krate: krate.name,
-                });
-            }
-        }
+        builder.ensure(CrateLibrustc { compiler, target: run.target, test_kind, krate });
     }
 
     fn run(self, builder: &Builder<'_>) {
@@ -1947,24 +1937,10 @@ impl Step for Crate {
     fn make_run(run: RunConfig<'_>) {
         let builder = run.builder;
         let compiler = builder.compiler(builder.top_stage, run.build_triple());
+        let test_kind = builder.kind.into();
+        let krate = builder.crate_paths[&run.path];
 
-        let make = |mode: Mode, krate: &CargoCrate| {
-            let test_kind = builder.kind.into();
-
-            builder.ensure(Crate {
-                compiler,
-                target: run.target,
-                mode,
-                test_kind,
-                krate: krate.name,
-            });
-        };
-
-        for krate in builder.in_tree_crates("test", Some(run.target)) {
-            if krate.path.ends_with(&run.path) {
-                make(Mode::Std, krate);
-            }
-        }
+        builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, test_kind, krate });
     }
 
     /// Runs all unit tests plus documentation tests for a given crate defined
@@ -2392,10 +2368,6 @@ impl Step for Bootstrap {
             .current_dir(builder.src.join("src/bootstrap"))
             .env("RUSTFLAGS", "-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
-            // HACK: bootstrap's tests want to know the output directory, but there's no way to set
-            // it except through config.toml. Set it through an env variable instead.
-            .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out)
-            .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo)
             .env("RUSTC_BOOTSTRAP", "1")
             .env("RUSTC", &builder.initial_rustc);
         if let Some(flags) = option_env!("RUSTFLAGS") {
diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
new file mode 100644
index 00000000000..d465724326e
--- /dev/null
+++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff
@@ -0,0 +1,100 @@
+- // MIR for `main` before Derefer
++ // MIR for `main` after Derefer
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/derefer_test_multiple.rs:2:12: 2:12
+      let mut _1: (i32, i32);              // in scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+      let mut _3: &mut (i32, i32);         // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+      let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+      let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28
++     let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _12: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++     let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++     let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++     let mut _15: &mut (i32, i32);        // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+          let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+          scope 2 {
+              debug b => _2;               // in scope 2 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+              let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+              scope 3 {
+                  debug c => _4;           // in scope 3 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+                  let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+                  scope 4 {
+                      debug d => _6;       // in scope 4 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+                      let _8: &mut i32;    // in scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+                      scope 5 {
+                          debug x => _8;   // in scope 5 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+                          let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+                          scope 6 {
+                              debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14
+          (_1.0: i32) = const 42_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          (_1.1: i32) = const 43_i32;      // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25
+          StorageLive(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14
+          StorageLive(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+          _3 = &mut _1;                    // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28
+          (_2.0: i32) = const 99_i32;      // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29
+          StorageDead(_3);                 // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29
+          StorageLive(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14
+          StorageLive(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+          _5 = &mut _2;                    // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28
+          (_4.0: i32) = const 11_i32;      // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29
+          StorageDead(_5);                 // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29
+          StorageLive(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14
+          StorageLive(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
+          _7 = &mut _4;                    // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28
+          (_6.0: i32) = const 13_i32;      // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29
+          StorageDead(_7);                 // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29
+          StorageLive(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10
+-         _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_10);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_11);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageLive(_12);                // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         _8 = &mut ((*_12).1: i32);       // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30
++         StorageDead(_10);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
++         StorageDead(_11);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
++         StorageDead(_12);                // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+          StorageLive(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10
+-         _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_13);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_14);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageLive(_15);                // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         _9 = &mut ((*_15).1: i32);       // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30
++         StorageDead(_13);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
++         StorageDead(_14);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
++         StorageDead(_15);                // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
+          _0 = const ();                   // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2
+          StorageDead(_9);                 // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_8);                 // scope 4 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_6);                 // scope 3 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_4);                 // scope 2 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_2);                 // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          StorageDead(_1);                 // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2
+          return;                          // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2
++     }
++ 
++     bb1 (cleanup): {
++         resume;                          // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs
new file mode 100644
index 00000000000..a27363447fe
--- /dev/null
+++ b/src/test/mir-opt/derefer_test_multiple.rs
@@ -0,0 +1,9 @@
+// EMIT_MIR derefer_test_multiple.main.Derefer.diff
+fn main () {
+    let mut a = (42, 43);
+    let mut b = (99, &mut a);
+    let mut c = (11, &mut b);
+    let mut d = (13, &mut c);
+    let x = &mut (*d.1).1.1.1;
+    let y = &mut (*d.1).1.1.1;
+}
diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr
new file mode 100644
index 00000000000..615fffcd578
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs
new file mode 100644
index 00000000000..40f013f6a78
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs
@@ -0,0 +1,4 @@
+fn main() {
+    let mut vec = vec![0u32; 420];
+    vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable
+}
diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr
new file mode 100644
index 00000000000..e3a16eddfd5
--- /dev/null
+++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr
@@ -0,0 +1,24 @@
+error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ----^^^^^^^^^-----
+   |     |   |
+   |     |   immutable borrow occurs here
+   |     mutable borrow occurs here
+   |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:9
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |         ^^^^^^^^^
+help: ...and then using that local here
+  --> $DIR/suggest-storing-local-var-for-vector.rs:3:5
+   |
+LL |     vec[vec.len() - 1] = 123;
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0502`.
diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
index 50d277a12f7..0f2daaf99d9 100644
--- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
+++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr
@@ -54,6 +54,17 @@ LL |     i[i[3]] = 4;
    |     | immutable borrow occurs here
    |     mutable borrow occurs here
    |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+   |
+LL |     i[i[3]] = 4;
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:138:5
+   |
+LL |     i[i[3]] = 4;
+   |     ^^^^^^^
 
 error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
   --> $DIR/two-phase-nonrecv-autoref.rs:143:7
@@ -64,6 +75,17 @@ LL |     i[i[3]] = i[4];
    |     | immutable borrow occurs here
    |     mutable borrow occurs here
    |     mutable borrow later used here
+   |
+help: try adding a local storing this...
+  --> $DIR/two-phase-nonrecv-autoref.rs:143:7
+   |
+LL |     i[i[3]] = i[4];
+   |       ^^^^
+help: ...and then using that local here
+  --> $DIR/two-phase-nonrecv-autoref.rs:143:5
+   |
+LL |     i[i[3]] = i[4];
+   |     ^^^^^^^
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
index 8431d989278..48e12e903b8 100644
--- a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
+++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr
@@ -8,6 +8,9 @@ LL |     let _ = A;
 note: required by a bound in `A`
   --> $DIR/unused-substs-1.rs:9:11
    |
+LL | struct A<const N: usize>
+   |        - required by a bound in this
+LL | where
 LL |     A<N>: Bar<N>;
    |           ^^^^^^ required by this bound in `A`
 
diff --git a/src/test/ui/error-codes/E0516.stderr b/src/test/ui/error-codes/E0516.stderr
index 2e6de5053d5..5243b7caf22 100644
--- a/src/test/ui/error-codes/E0516.stderr
+++ b/src/test/ui/error-codes/E0516.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let x: typeof(92) = 92;
    |            ^^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let x: i32 = 92;
+   |            ~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-29184.stderr b/src/test/ui/issues/issue-29184.stderr
index 87d3632ee42..75b6c64f2ce 100644
--- a/src/test/ui/issues/issue-29184.stderr
+++ b/src/test/ui/issues/issue-29184.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let x: typeof(92) = 92;
    |            ^^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let x: i32 = 92;
+   |            ~~~
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
index 489cb03ddd3..e7a6c1837bd 100644
--- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
+++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr
@@ -9,7 +9,7 @@ note: the lint level is defined here
    |
 LL | #![deny(lossy_provenance_casts)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
-   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
 error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32`
   --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22
@@ -17,7 +17,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons
 LL |     let addr_32bit = &x as *const u8 as u32;
    |                      ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32`
    |
-   = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead
+   = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/typeof/type_mismatch.stderr b/src/test/ui/typeof/type_mismatch.stderr
index e82b5e44973..e75214cd31a 100644
--- a/src/test/ui/typeof/type_mismatch.stderr
+++ b/src/test/ui/typeof/type_mismatch.stderr
@@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented
    |
 LL |     let b: typeof(a) = 1i8;
    |            ^^^^^^^^^ reserved keyword
+   |
+help: consider replacing `typeof(...)` with an actual type
+   |
+LL |     let b: u8 = 1i8;
+   |            ~~
 
 error[E0308]: mismatched types
   --> $DIR/type_mismatch.rs:5:24
diff --git a/src/tools/miri b/src/tools/miri
-Subproject be72564a643758afcc1de152ead2359d489149c
+Subproject c568f32f165d86aba51ec544756c3c833acbabd