about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-15 20:04:49 +0000
committerbors <bors@rust-lang.org>2024-08-15 20:04:49 +0000
commit2c93fabd98d2c183bcb3afed1f7d51b2517ac5ed (patch)
tree13c751c5f4e50f36688d181702032d81dcb7b9fe
parentd2b5aa6552c8acf67f38a2ad92062a32ec542f08 (diff)
parentef72a6a7111731049e840c129fc3db4838df5352 (diff)
Auto merge of #129130 - matthiaskrgr:rollup-603jta0, r=matthiaskrgr
Rollup of 8 pull requests

Successful merges:

 - #128348 (Unconditionally allow shadow call-stack sanitizer for AArch64)
 - #129065 (Use `impl PartialEq<TokenKind> for Token` more.)
 - #129072 (Infer async closure args from `Fn` bound even if there is no corresponding `Future` bound on return)
 - #129096 (Print more verbose error for commands that capture output)
 - #129101 (Fix projections when parent capture is by-ref but child capture is by-value in the `ByMoveBody` pass)
 - #129106 (Remove redundant type ops: `Eq`/`Subtype`)
 - #129122 (Remove duplicated `Rustdoc::output` method from `run-make-support` lib)
 - #129124 (rustdoc-json: Use FxHashMap from rustdoc_json_types)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs45
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs27
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs54
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs2
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs55
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs71
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs2
-rw-r--r--compiler/rustc_parse/src/parser/item.rs38
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs8
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs20
-rw-r--r--compiler/rustc_parse/src/parser/path.rs8
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs4
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs17
-rw-r--r--compiler/rustc_session/src/session.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs33
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs30
-rw-r--r--compiler/rustc_traits/src/type_op.rs24
-rw-r--r--src/bootstrap/src/lib.rs26
-rw-r--r--src/bootstrap/src/utils/exec.rs10
-rw-r--r--src/doc/rustc/src/platform-support/android.md5
-rw-r--r--src/doc/unstable-book/src/compiler-flags/fixed-x18.md7
-rw-r--r--src/doc/unstable-book/src/compiler-flags/sanitizer.md4
-rw-r--r--src/librustdoc/json/mod.rs10
-rw-r--r--src/rustdoc-json-types/lib.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs4
-rw-r--r--src/tools/run-make-support/src/external_deps/rustdoc.rs8
-rw-r--r--src/tools/rustfmt/src/parse/macros/mod.rs8
-rw-r--r--tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs19
-rw-r--r--tests/run-make/deref-impl-rustdoc-ice/rmake.rs2
-rw-r--r--tests/run-make/emit-shared-files/rmake.rs6
-rw-r--r--tests/run-make/exit-code/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-determinism/rmake.rs8
-rw-r--r--tests/run-make/rustdoc-io-error/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-map-file/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-output-path/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-output-stdout/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-scrape-examples-macros/rmake.rs4
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/scrape.rs4
-rw-r--r--tests/run-make/rustdoc-target-spec-json-path/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-themes/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-with-out-dir-option/rmake.rs2
-rw-r--r--tests/ui/abi/shadow-call-stack-without-fixed-x18.rs15
-rw-r--r--tests/ui/async-await/async-closures/move-out-of-ref.rs16
-rw-r--r--tests/ui/async-await/async-closures/move-out-of-ref.stderr18
-rw-r--r--tests/ui/async-await/async-closures/sig-from-bare-fn.rs49
50 files changed, 396 insertions, 306 deletions
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index ed54c0c8662..ae2627d6938 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -328,7 +328,7 @@ pub fn parse_asm_args<'a>(
 /// Otherwise, the suggestion will be incorrect.
 fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
     // Tool-only output
-    let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+    let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
     p.dcx().emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
 }
 
@@ -338,7 +338,7 @@ fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
 /// Otherwise, the suggestion will be incorrect.
 fn err_unsupported_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
     // Tool-only output
-    let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+    let full_span = if p.token == token::Comma { span.to(p.token.span) } else { span };
     p.dcx().emit_err(errors::GlobalAsmUnsupportedOption { span, symbol, full_span });
 }
 
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 6f177107e70..256713ef730 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1154,7 +1154,7 @@ fn check_matcher_core<'tt>(
                         && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true }))
                         && matches!(
                             next_token,
-                            TokenTree::Token(token) if token.kind == BinOp(token::BinOpToken::Or)
+                            TokenTree::Token(token) if *token == BinOp(token::BinOpToken::Or)
                         )
                     {
                         // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param.
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 589a9c5a719..6b813dc64ce 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -14,7 +14,7 @@ use rustc_middle::span_bug;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::error_reporting::traits::ArgKind;
 use rustc_trait_selection::traits;
@@ -539,6 +539,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// we identify the `FnOnce<Args, Output = ?Fut>` bound, and if the output type is
     /// an inference variable `?Fut`, we check if that is bounded by a `Future<Output = Ty>`
     /// projection.
+    ///
+    /// This function is actually best-effort with the return type; if we don't find a
+    /// `Future` projection, we still will return arguments that we extracted from the `FnOnce`
+    /// projection, and the output will be an unconstrained type variable instead.
     fn extract_sig_from_projection_and_future_bound(
         &self,
         cause_span: Option<Span>,
@@ -564,24 +568,43 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare.
+        let mut return_ty = None;
         for bound in self.obligations_for_self_ty(return_vid) {
             if let Some(ret_projection) = bound.predicate.as_projection_clause()
                 && let Some(ret_projection) = ret_projection.no_bound_vars()
                 && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput)
             {
-                let sig = projection.rebind(self.tcx.mk_fn_sig(
-                    input_tys,
-                    ret_projection.term.expect_type(),
-                    false,
-                    hir::Safety::Safe,
-                    Abi::Rust,
-                ));
-
-                return Some(ExpectedSig { cause_span, sig });
+                return_ty = Some(ret_projection.term.expect_type());
+                break;
             }
         }
 
-        None
+        // SUBTLE: If we didn't find a `Future<Output = ...>` bound for the return
+        // vid, we still want to attempt to provide inference guidance for the async
+        // closure's arguments. Instantiate a new vid to plug into the output type.
+        //
+        // You may be wondering, what if it's higher-ranked? Well, given that we
+        // found a type variable for the `FnOnce::Output` projection above, we know
+        // that the output can't mention any of the vars.
+        //
+        // Also note that we use a fresh var here for the signature since the signature
+        // records the output of the *future*, and `return_vid` above is the type
+        // variable of the future, not its output.
+        //
+        // FIXME: We probably should store this signature inference output in a way
+        // that does not misuse a `FnSig` type, but that can be done separately.
+        let return_ty =
+            return_ty.unwrap_or_else(|| self.next_ty_var(cause_span.unwrap_or(DUMMY_SP)));
+
+        let sig = projection.rebind(self.tcx.mk_fn_sig(
+            input_tys,
+            return_ty,
+            false,
+            hir::Safety::Safe,
+            Abi::Rust,
+        ));
+
+        return Some(ExpectedSig { cause_span, sig });
     }
 
     fn sig_of_closure(
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6b36944b208..5f6e7fb314d 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1853,7 +1853,7 @@ impl KeywordIdents {
                         if !prev_dollar {
                             self.check_ident_token(cx, UnderMacro(true), ident);
                         }
-                    } else if token.kind == TokenKind::Dollar {
+                    } else if *token == TokenKind::Dollar {
                         prev_dollar = true;
                         continue;
                     }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 075eae02904..92c8d265c09 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -65,10 +65,9 @@ use crate::query::plumbing::{
 };
 use crate::traits::query::{
     CanonicalAliasGoal, CanonicalPredicateGoal, CanonicalTyGoal,
-    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
-    CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, DropckConstraint,
-    DropckOutlivesResult, MethodAutoderefStepsResult, NoSolution, NormalizationResult,
-    OutlivesBound,
+    CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpNormalizeGoal,
+    CanonicalTypeOpProvePredicateGoal, DropckConstraint, DropckOutlivesResult,
+    MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound,
 };
 use crate::traits::{
     specialization_graph, CodegenObligationError, EvaluationResult, ImplSource,
@@ -2090,26 +2089,6 @@ rustc_queries! {
         desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
     }
 
-    /// Do not call this query directly: part of the `Eq` type-op
-    query type_op_eq(
-        goal: CanonicalTypeOpEqGoal<'tcx>
-    ) -> Result<
-        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
-        NoSolution,
-    > {
-        desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
-    }
-
-    /// Do not call this query directly: part of the `Subtype` type-op
-    query type_op_subtype(
-        goal: CanonicalTypeOpSubtypeGoal<'tcx>
-    ) -> Result<
-        &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
-        NoSolution,
-    > {
-        desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
-    }
-
     /// Do not call this query directly: part of the `ProvePredicate` type-op
     query type_op_prove_predicate(
         goal: CanonicalTypeOpProvePredicateGoal<'tcx>
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 69d21a63f55..7ea36f08232 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -78,6 +78,8 @@ use rustc_middle::mir::{self, dump_mir, MirPass};
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 
+use crate::pass_manager::validate_body;
+
 pub struct ByMoveBody;
 
 impl<'tcx> MirPass<'tcx> for ByMoveBody {
@@ -131,20 +133,40 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
             |(parent_field_idx, parent_capture), (child_field_idx, child_capture)| {
                 // Store this set of additional projections (fields and derefs).
                 // We need to re-apply them later.
-                let child_precise_captures =
-                    &child_capture.place.projections[parent_capture.place.projections.len()..];
+                let mut child_precise_captures = child_capture.place.projections
+                    [parent_capture.place.projections.len()..]
+                    .to_vec();
 
-                // If the parent captures by-move, and the child captures by-ref, then we
-                // need to peel an additional `deref` off of the body of the child.
-                let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref();
-                if needs_deref {
-                    assert_ne!(
-                        coroutine_kind,
-                        ty::ClosureKind::FnOnce,
+                // If the parent capture is by-ref, then we need to apply an additional
+                // deref before applying any further projections to this place.
+                if parent_capture.is_by_ref() {
+                    child_precise_captures.insert(
+                        0,
+                        Projection { ty: parent_capture.place.ty(), kind: ProjectionKind::Deref },
+                    );
+                }
+                // If the child capture is by-ref, then we need to apply a "ref"
+                // projection (i.e. `&`) at the end. But wait! We don't have that
+                // as a projection kind. So instead, we can apply its dual and
+                // *peel* a deref off of the place when it shows up in the MIR body.
+                // Luckily, by construction this is always possible.
+                let peel_deref = if child_capture.is_by_ref() {
+                    assert!(
+                        parent_capture.is_by_ref() || coroutine_kind != ty::ClosureKind::FnOnce,
                         "`FnOnce` coroutine-closures return coroutines that capture from \
                         their body; it will always result in a borrowck error!"
                     );
-                }
+                    true
+                } else {
+                    false
+                };
+
+                // Regarding the behavior above, you may think that it's redundant to both
+                // insert a deref and then peel a deref if the parent and child are both
+                // captured by-ref. This would be correct, except for the case where we have
+                // precise capturing projections, since the inserted deref is to the *beginning*
+                // and the peeled deref is at the *end*. I cannot seem to actually find a
+                // case where this happens, though, but let's keep this code flexible.
 
                 // Finally, store the type of the parent's captured place. We need
                 // this when building the field projection in the MIR body later on.
@@ -164,7 +186,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                     (
                         FieldIdx::from_usize(parent_field_idx + num_args),
                         parent_capture_ty,
-                        needs_deref,
+                        peel_deref,
                         child_precise_captures,
                     ),
                 )
@@ -192,6 +214,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
         dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
+
+        // Let's just always validate this body.
+        validate_body(tcx, &mut by_move_body, "Initial coroutine_by_move body".to_string());
+
         // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body.
         by_move_body.source = mir::MirSource::from_instance(InstanceKind::CoroutineKindShim {
             coroutine_def_id: coroutine_def_id.to_def_id(),
@@ -202,7 +228,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
 
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
-    field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
+    field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, Vec<Projection<'tcx>>)>,
     by_move_coroutine_ty: Ty<'tcx>,
 }
 
@@ -223,14 +249,14 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> {
         if place.local == ty::CAPTURE_STRUCT_LOCAL
             && let Some((&mir::ProjectionElem::Field(idx, _), projection)) =
                 place.projection.split_first()
-            && let Some(&(remapped_idx, remapped_ty, needs_deref, bridging_projections)) =
+            && let Some(&(remapped_idx, remapped_ty, peel_deref, ref bridging_projections)) =
                 self.field_remapping.get(&idx)
         {
             // As noted before, if the parent closure captures a field by value, and
             // the child captures a field by ref, then for the by-move body we're
             // generating, we also are taking that field by value. Peel off a deref,
             // since a layer of ref'ing has now become redundant.
-            let final_projections = if needs_deref {
+            let final_projections = if peel_deref {
                 let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first()
                 else {
                     bug!(
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index fb4ed5b93b2..e7a7105803f 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -229,7 +229,7 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> {
             } else {
                 let this_spacing = if next_tok.is_punct() {
                     Spacing::Joint
-                } else if next_tok.kind == token::Eof {
+                } else if next_tok == token::Eof {
                     Spacing::Alone
                 } else {
                     Spacing::JointHidden
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 8fdfbcee385..645fde25cd4 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -162,7 +162,7 @@ impl<'a> Parser<'a> {
         }
         loop {
             // skip any other attributes, we want the item
-            if snapshot.token.kind == token::Pound {
+            if snapshot.token == token::Pound {
                 if let Err(err) = snapshot.parse_attribute(InnerAttrPolicy::Permitted) {
                     err.cancel();
                     return Some(replacement_span);
@@ -343,7 +343,7 @@ impl<'a> Parser<'a> {
 
         // Presumably, the majority of the time there will only be one attr.
         let mut expanded_attrs = Vec::with_capacity(1);
-        while self.token.kind != token::Eof {
+        while self.token != token::Eof {
             let lo = self.token.span;
             let item = self.parse_attr_item(ForceCollect::Yes)?;
             expanded_attrs.push((item, lo.to(self.prev_token.span)));
@@ -359,7 +359,7 @@ impl<'a> Parser<'a> {
     pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::NestedMetaItem>> {
         // Presumably, the majority of the time there will only be one attr.
         let mut nmis = ThinVec::with_capacity(1);
-        while self.token.kind != token::Eof {
+        while self.token != token::Eof {
             nmis.push(self.parse_meta_item_inner()?);
             if !self.eat(&token::Comma) {
                 break;
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 47ca85ba060..ba4e222a41a 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -474,8 +474,8 @@ impl<'a> Parser<'a> {
                     // If this isn't the case however, and the suggestion is a token the
                     // content of which is the same as the found token's, we remove it as well.
                     if !eq {
-                        if let TokenType::Token(kind) = &token {
-                            if kind == &self.token.kind {
+                        if let TokenType::Token(kind) = token {
+                            if self.token == *kind {
                                 return false;
                             }
                         }
@@ -506,7 +506,7 @@ impl<'a> Parser<'a> {
             } else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
                 // The current token is in the same line as the prior token, not recoverable.
             } else if [token::Comma, token::Colon].contains(&self.token.kind)
-                && self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis)
+                && self.prev_token == token::CloseDelim(Delimiter::Parenthesis)
             {
                 // Likely typo: The current token is on a new line and is expected to be
                 // `.`, `;`, `?`, or an operator after a close delimiter token.
@@ -518,7 +518,7 @@ impl<'a> Parser<'a> {
                 // https://github.com/rust-lang/rust/issues/72253
             } else if self.look_ahead(1, |t| {
                 t == &token::CloseDelim(Delimiter::Brace)
-                    || t.can_begin_expr() && t.kind != token::Colon
+                    || t.can_begin_expr() && *t != token::Colon
             }) && [token::Comma, token::Colon].contains(&self.token.kind)
             {
                 // Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
@@ -562,7 +562,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        if self.token.kind == TokenKind::EqEq
+        if self.token == TokenKind::EqEq
             && self.prev_token.is_ident()
             && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
         {
@@ -655,9 +655,9 @@ impl<'a> Parser<'a> {
         // positive for a `cr#` that wasn't intended to start a c-string literal, but identifying
         // that in the parser requires unbounded lookahead, so we only add a hint to the existing
         // error rather than replacing it entirely.
-        if ((self.prev_token.kind == TokenKind::Ident(sym::c, IdentIsRaw::No)
+        if ((self.prev_token == TokenKind::Ident(sym::c, IdentIsRaw::No)
             && matches!(&self.token.kind, TokenKind::Literal(token::Lit { kind: token::Str, .. })))
-            || (self.prev_token.kind == TokenKind::Ident(sym::cr, IdentIsRaw::No)
+            || (self.prev_token == TokenKind::Ident(sym::cr, IdentIsRaw::No)
                 && matches!(
                     &self.token.kind,
                     TokenKind::Literal(token::Lit { kind: token::Str, .. }) | token::Pound
@@ -673,7 +673,7 @@ impl<'a> Parser<'a> {
         // `pub` may be used for an item or `pub(crate)`
         if self.prev_token.is_ident_named(sym::public)
             && (self.token.can_begin_item()
-                || self.token.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+                || self.token == TokenKind::OpenDelim(Delimiter::Parenthesis))
         {
             err.span_suggestion_short(
                 self.prev_token.span,
@@ -772,7 +772,7 @@ impl<'a> Parser<'a> {
             ),
         );
         if self.token == token::Pound
-            && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Bracket))
+            && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
         {
             // We have
             // #[attr]
@@ -867,7 +867,7 @@ impl<'a> Parser<'a> {
                 let str_span = self.prev_token.span;
                 let mut span = self.token.span;
                 let mut count = 0;
-                while self.token.kind == TokenKind::Pound
+                while self.token == TokenKind::Pound
                     && !sm.is_multiline(span.shrink_to_hi().until(self.token.span.shrink_to_lo()))
                 {
                     span = span.with_hi(self.token.span.hi());
@@ -1167,7 +1167,7 @@ impl<'a> Parser<'a> {
             return;
         }
 
-        if token::PathSep == self.token.kind && segment.args.is_none() {
+        if self.token == token::PathSep && segment.args.is_none() {
             let snapshot = self.create_snapshot_for_diagnostic();
             self.bump();
             let lo = self.token.span;
@@ -1176,13 +1176,11 @@ impl<'a> Parser<'a> {
                     let span = lo.to(self.prev_token.span);
                     // Detect trailing `>` like in `x.collect::Vec<_>>()`.
                     let mut trailing_span = self.prev_token.span.shrink_to_hi();
-                    while self.token.kind == token::BinOp(token::Shr)
-                        || self.token.kind == token::Gt
-                    {
+                    while self.token == token::BinOp(token::Shr) || self.token == token::Gt {
                         trailing_span = trailing_span.to(self.token.span);
                         self.bump();
                     }
-                    if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+                    if self.token == token::OpenDelim(Delimiter::Parenthesis) {
                         // Recover from bad turbofish: `foo.collect::Vec<_>()`.
                         segment.args = Some(AngleBracketedArgs { args, span }.into());
 
@@ -1430,7 +1428,7 @@ impl<'a> Parser<'a> {
                             self.restore_snapshot(snapshot);
                         }
                     }
-                    return if token::PathSep == self.token.kind {
+                    return if self.token == token::PathSep {
                         // We have some certainty that this was a bad turbofish at this point.
                         // `foo< bar >::`
                         if let ExprKind::Binary(o, ..) = inner_op.kind
@@ -1462,7 +1460,7 @@ impl<'a> Parser<'a> {
                                 Err(self.dcx().create_err(err))
                             }
                         }
-                    } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
+                    } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
                         // We have high certainty that this was a bad turbofish at this point.
                         // `foo< bar >(`
                         if let ExprKind::Binary(o, ..) = inner_op.kind
@@ -1528,7 +1526,7 @@ impl<'a> Parser<'a> {
         ];
         self.consume_tts(1, &modifiers);
 
-        if self.token.kind == token::Eof {
+        if self.token == token::Eof {
             // Not entirely sure that what we consumed were fn arguments, rollback.
             self.restore_snapshot(snapshot);
             Err(())
@@ -1811,7 +1809,7 @@ impl<'a> Parser<'a> {
     /// This function gets called in places where a semicolon is NOT expected and if there's a
     /// semicolon it emits the appropriate error and returns true.
     pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
-        if self.token.kind != TokenKind::Semi {
+        if self.token != TokenKind::Semi {
             return false;
         }
 
@@ -2405,10 +2403,10 @@ impl<'a> Parser<'a> {
         modifier: &[(token::TokenKind, i64)],
     ) {
         while acc > 0 {
-            if let Some((_, val)) = modifier.iter().find(|(t, _)| *t == self.token.kind) {
+            if let Some((_, val)) = modifier.iter().find(|(t, _)| self.token == *t) {
                 acc += *val;
             }
-            if self.token.kind == token::Eof {
+            if self.token == token::Eof {
                 break;
             }
             self.bump();
@@ -2598,7 +2596,7 @@ impl<'a> Parser<'a> {
                 }
             })
             .is_some()
-            || self.token.kind == TokenKind::Dot;
+            || self.token == TokenKind::Dot;
         // This will be true when a trait object type `Foo +` or a path which was a `const fn` with
         // type params has been parsed.
         let was_op =
@@ -2617,7 +2615,7 @@ impl<'a> Parser<'a> {
         })() {
             Ok(expr) => {
                 // Find a mistake like `MyTrait<Assoc == S::Assoc>`.
-                if token::EqEq == snapshot.token.kind {
+                if snapshot.token == token::EqEq {
                     err.span_suggestion(
                         snapshot.token.span,
                         "if you meant to use an associated type binding, replace `==` with `=`",
@@ -2627,7 +2625,7 @@ impl<'a> Parser<'a> {
                     let guar = err.emit();
                     let value = self.mk_expr_err(start.to(expr.span), guar);
                     return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }));
-                } else if token::Colon == snapshot.token.kind
+                } else if snapshot.token == token::Colon
                     && expr.span.lo() == snapshot.token.span.hi()
                     && matches!(expr.kind, ExprKind::Path(..))
                 {
@@ -2642,8 +2640,7 @@ impl<'a> Parser<'a> {
                     return Ok(GenericArg::Type(
                         self.mk_ty(start.to(expr.span), TyKind::Err(guar)),
                     ));
-                } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg()
-                {
+                } else if self.token == token::Comma || self.token.kind.should_end_const_arg() {
                     // Avoid the following output by checking that we consumed a full const arg:
                     // help: expressions must be enclosed in braces to be used as const generic
                     //       arguments
@@ -2846,8 +2843,8 @@ impl<'a> Parser<'a> {
     pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
         // Check for `'a : {`
         if !(self.check_lifetime()
-            && self.look_ahead(1, |tok| tok.kind == token::Colon)
-            && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Brace)))
+            && self.look_ahead(1, |t| *t == token::Colon)
+            && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)))
         {
             return false;
         }
@@ -3001,7 +2998,7 @@ impl<'a> Parser<'a> {
         // >>>>>>>
         let mut end = None;
         loop {
-            if self.token.kind == TokenKind::Eof {
+            if self.token == TokenKind::Eof {
                 break;
             }
             if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or))
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index cf5d65708ab..536160c8136 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -165,7 +165,7 @@ impl<'a> Parser<'a> {
 
             // Look for JS' `===` and `!==` and recover
             if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual)
-                && self.token.kind == token::Eq
+                && self.token == token::Eq
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
@@ -190,7 +190,7 @@ impl<'a> Parser<'a> {
 
             // Look for PHP's `<>` and recover
             if op.node == AssocOp::Less
-                && self.token.kind == token::Gt
+                && self.token == token::Gt
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
@@ -208,7 +208,7 @@ impl<'a> Parser<'a> {
 
             // Look for C++'s `<=>` and recover
             if op.node == AssocOp::LessEqual
-                && self.token.kind == token::Gt
+                && self.token == token::Gt
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
@@ -882,7 +882,7 @@ impl<'a> Parser<'a> {
         let mut res = ensure_sufficient_stack(|| {
             loop {
                 let has_question =
-                    if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+                    if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
                         // We are using noexpect here because we don't expect a `?` directly after
                         // a `return` which could be suggested otherwise.
                         self.eat_noexpect(&token::Question)
@@ -894,20 +894,19 @@ impl<'a> Parser<'a> {
                     e = self.mk_expr(lo.to(self.prev_token.span), ExprKind::Try(e));
                     continue;
                 }
-                let has_dot =
-                    if self.prev_token.kind == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
-                        // We are using noexpect here because we don't expect a `.` directly after
-                        // a `return` which could be suggested otherwise.
-                        self.eat_noexpect(&token::Dot)
-                    } else if self.token.kind == TokenKind::RArrow && self.may_recover() {
-                        // Recovery for `expr->suffix`.
-                        self.bump();
-                        let span = self.prev_token.span;
-                        self.dcx().emit_err(errors::ExprRArrowCall { span });
-                        true
-                    } else {
-                        self.eat(&token::Dot)
-                    };
+                let has_dot = if self.prev_token == TokenKind::Ident(kw::Return, IdentIsRaw::No) {
+                    // We are using noexpect here because we don't expect a `.` directly after
+                    // a `return` which could be suggested otherwise.
+                    self.eat_noexpect(&token::Dot)
+                } else if self.token == TokenKind::RArrow && self.may_recover() {
+                    // Recovery for `expr->suffix`.
+                    self.bump();
+                    let span = self.prev_token.span;
+                    self.dcx().emit_err(errors::ExprRArrowCall { span });
+                    true
+                } else {
+                    self.eat(&token::Dot)
+                };
                 if has_dot {
                     // expr.f
                     e = self.parse_dot_suffix_expr(lo, e)?;
@@ -1206,7 +1205,7 @@ impl<'a> Parser<'a> {
     }
 
     fn mk_expr_tuple_field_access(
-        &mut self,
+        &self,
         lo: Span,
         ident_span: Span,
         base: P<Expr>,
@@ -1221,7 +1220,7 @@ impl<'a> Parser<'a> {
 
     /// Parse a function call expression, `expr(...)`.
     fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
-        let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+        let snapshot = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
         } else {
             None
@@ -1585,7 +1584,7 @@ impl<'a> Parser<'a> {
                 // Suggests using '<=' if there is an error parsing qpath when the previous token
                 // is an '=' token. Only emits suggestion if the '<' token and '=' token are
                 // directly adjacent (i.e. '=<')
-                if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+                if maybe_eq_tok == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
                     let eq_lt = maybe_eq_tok.span.to(lt_span);
                     err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
                 }
@@ -2230,7 +2229,7 @@ impl<'a> Parser<'a> {
             return Ok(());
         }
 
-        if self.token.kind == token::Comma {
+        if self.token == token::Comma {
             if !self.psess.source_map().is_multiline(prev_span.until(self.token.span)) {
                 return Ok(());
             }
@@ -2360,7 +2359,7 @@ impl<'a> Parser<'a> {
             None => {}
         }
 
-        if self.token.kind == TokenKind::Semi
+        if self.token == TokenKind::Semi
             && matches!(self.token_cursor.stack.last(), Some((.., Delimiter::Parenthesis)))
             && self.may_recover()
         {
@@ -2557,7 +2556,7 @@ impl<'a> Parser<'a> {
                             );
                         } else {
                             // Look for usages of '=>' where '>=' might be intended
-                            if maybe_fatarrow.kind == token::FatArrow {
+                            if maybe_fatarrow == token::FatArrow {
                                 err.span_suggestion(
                                     maybe_fatarrow.span,
                                     "you might have meant to write a \"greater than or equal to\" comparison",
@@ -2606,7 +2605,7 @@ impl<'a> Parser<'a> {
                 missing_let: None,
                 comparison: None,
             };
-            if self.prev_token.kind == token::BinOp(token::Or) {
+            if self.prev_token == token::BinOp(token::Or) {
                 // This was part of a closure, the that part of the parser recover.
                 return Err(self.dcx().create_err(err));
             } else {
@@ -2742,7 +2741,7 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
-        let begin_paren = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+        let begin_paren = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             // Record whether we are about to parse `for (`.
             // This is used below for recovery in case of `for ( $stuff ) $block`
             // in which case we will suggest `for $stuff $block`.
@@ -2776,7 +2775,7 @@ impl<'a> Parser<'a> {
                         return Err(err);
                     }
                 };
-                return if self.token.kind == token::CloseDelim(Delimiter::Parenthesis) {
+                return if self.token == token::CloseDelim(Delimiter::Parenthesis) {
                     // We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
                     // parser state and emit a targeted suggestion.
                     let span = vec![start_span, self.token.span];
@@ -2995,7 +2994,7 @@ impl<'a> Parser<'a> {
         first_expr: &P<Expr>,
         arrow_span: Span,
     ) -> Option<(Span, ErrorGuaranteed)> {
-        if self.token.kind != token::Semi {
+        if self.token != token::Semi {
             return None;
         }
         let start_snapshot = self.create_snapshot_for_diagnostic();
@@ -3024,18 +3023,18 @@ impl<'a> Parser<'a> {
         // We might have either a `,` -> `;` typo, or a block without braces. We need
         // a more subtle parsing strategy.
         loop {
-            if self.token.kind == token::CloseDelim(Delimiter::Brace) {
+            if self.token == token::CloseDelim(Delimiter::Brace) {
                 // We have reached the closing brace of the `match` expression.
                 return Some(err(self, stmts));
             }
-            if self.token.kind == token::Comma {
+            if self.token == token::Comma {
                 self.restore_snapshot(start_snapshot);
                 return None;
             }
             let pre_pat_snapshot = self.create_snapshot_for_diagnostic();
             match self.parse_pat_no_top_alt(None, None) {
                 Ok(_pat) => {
-                    if self.token.kind == token::FatArrow {
+                    if self.token == token::FatArrow {
                         // Reached arm end.
                         self.restore_snapshot(pre_pat_snapshot);
                         return Some(err(self, stmts));
@@ -3286,7 +3285,7 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
-        if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
+        if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             // Detect and recover from `($pat if $cond) => $arm`.
             let left = self.token.span;
             match self.parse_pat_allow_top_alt(
@@ -3344,7 +3343,7 @@ impl<'a> Parser<'a> {
                     self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
                     let msg = "you might have meant to start a match arm after the match guard";
                     if self.eat(&token::CloseDelim(Delimiter::Brace)) {
-                        let applicability = if self.token.kind != token::FatArrow {
+                        let applicability = if self.token != token::FatArrow {
                             // We have high confidence that we indeed didn't have a struct
                             // literal in the match guard, but rather we had some operation
                             // that ended in a path, immediately followed by a block that was
@@ -3565,7 +3564,7 @@ impl<'a> Parser<'a> {
                         && self.look_ahead(1, |t| {
                             AssocOp::from_token(t).is_some()
                                 || matches!(t.kind, token::OpenDelim(_))
-                                || t.kind == token::Dot
+                                || *t == token::Dot
                         })
                     {
                         // Looks like they tried to write a shorthand, complex expression.
@@ -3850,11 +3849,11 @@ impl<'a> Parser<'a> {
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let res = f(this, attrs)?;
             let trailing = (this.restrictions.contains(Restrictions::STMT_EXPR)
-                 && this.token.kind == token::Semi)
+                 && this.token == token::Semi)
             // FIXME: pass an additional condition through from the place
             // where we know we need a comma, rather than assuming that
             // `#[attr] expr,` always captures a trailing comma.
-            || this.token.kind == token::Comma;
+            || this.token == token::Comma;
             Ok((res, trailing))
         })
     }
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 9124c15707d..f1bb7187e2f 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -393,7 +393,7 @@ impl<'a> Parser<'a> {
 
         if let Some(struct_) = struct_
             && self.may_recover()
-            && self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
+            && self.token == token::OpenDelim(Delimiter::Parenthesis)
         {
             snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
         };
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 8775d792c3d..e34e82bcd7b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -354,7 +354,7 @@ impl<'a> Parser<'a> {
     fn is_reuse_path_item(&mut self) -> bool {
         // no: `reuse ::path` for compatibility reasons with macro invocations
         self.token.is_keyword(kw::Reuse)
-            && self.look_ahead(1, |t| t.is_path_start() && t.kind != token::PathSep)
+            && self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep)
     }
 
     /// Are we sure this could not possibly be a macro invocation?
@@ -499,7 +499,7 @@ impl<'a> Parser<'a> {
         let mut err = self.dcx().struct_span_err(end.span, msg);
         if end.is_doc_comment() {
             err.span_label(end.span, "this doc comment doesn't document anything");
-        } else if self.token.kind == TokenKind::Semi {
+        } else if self.token == TokenKind::Semi {
             err.span_suggestion_verbose(
                 self.token.span,
                 "consider removing this semicolon",
@@ -777,12 +777,12 @@ impl<'a> Parser<'a> {
                         && self
                             .span_to_snippet(self.prev_token.span)
                             .is_ok_and(|snippet| snippet == "}")
-                        && self.token.kind == token::Semi;
+                        && self.token == token::Semi;
                     let mut semicolon_span = self.token.span;
                     if !is_unnecessary_semicolon {
                         // #105369, Detect spurious `;` before assoc fn body
                         is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace)
-                            && self.prev_token.kind == token::Semi;
+                            && self.prev_token == token::Semi;
                         semicolon_span = self.prev_token.span;
                     }
                     // We have to bail or we'll potentially never make progress.
@@ -1194,7 +1194,7 @@ impl<'a> Parser<'a> {
         // FIXME: This recovery should be tested better.
         if safety == Safety::Default
             && self.token.is_keyword(kw::Unsafe)
-            && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
+            && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
         {
             self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
             safety = Safety::Unsafe(self.token.span);
@@ -1258,7 +1258,7 @@ impl<'a> Parser<'a> {
             && self.is_keyword_ahead(1, &[kw::Extern])
             && self.look_ahead(
                 2 + self.look_ahead(2, |t| t.can_begin_string_literal() as usize),
-                |t| t.kind == token::OpenDelim(Delimiter::Brace),
+                |t| *t == token::OpenDelim(Delimiter::Brace),
             )
     }
 
@@ -1343,7 +1343,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, (Ident, StaticItem)> {
         let ident = self.parse_ident()?;
 
-        if self.token.kind == TokenKind::Lt && self.may_recover() {
+        if self.token == TokenKind::Lt && self.may_recover() {
             let generics = self.parse_generics()?;
             self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span });
         }
@@ -1914,7 +1914,7 @@ impl<'a> Parser<'a> {
                 let mut err = self.dcx().struct_span_err(sp, msg);
 
                 if self.token.is_ident()
-                    || (self.token.kind == TokenKind::Pound
+                    || (self.token == TokenKind::Pound
                         && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket))))
                 {
                     // This is likely another field, TokenKind::Pound is used for `#[..]`
@@ -1937,8 +1937,8 @@ impl<'a> Parser<'a> {
     fn expect_field_ty_separator(&mut self) -> PResult<'a, ()> {
         if let Err(err) = self.expect(&token::Colon) {
             let sm = self.psess.source_map();
-            let eq_typo = self.token.kind == token::Eq && self.look_ahead(1, |t| t.is_path_start());
-            let semi_typo = self.token.kind == token::Semi
+            let eq_typo = self.token == token::Eq && self.look_ahead(1, |t| t.is_path_start());
+            let semi_typo = self.token == token::Semi
                 && self.look_ahead(1, |t| {
                     t.is_path_start()
                     // We check that we are in a situation like `foo; bar` to avoid bad suggestions
@@ -1974,7 +1974,7 @@ impl<'a> Parser<'a> {
         attrs: AttrVec,
     ) -> PResult<'a, FieldDef> {
         let name = self.parse_field_ident(adt_ty, lo)?;
-        if self.token.kind == token::Not {
+        if self.token == token::Not {
             if let Err(mut err) = self.unexpected() {
                 // Encounter the macro invocation
                 err.subdiagnostic(MacroExpandsToAdtField { adt_ty });
@@ -1983,10 +1983,10 @@ impl<'a> Parser<'a> {
         }
         self.expect_field_ty_separator()?;
         let ty = self.parse_ty_for_field_def()?;
-        if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
+        if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) {
             self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span });
         }
-        if self.token.kind == token::Eq {
+        if self.token == token::Eq {
             self.bump();
             let const_expr = self.parse_expr_anon_const()?;
             let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
@@ -2064,7 +2064,7 @@ impl<'a> Parser<'a> {
                         .parse_ident_common(false)
                         // Cancel this error, we don't need it.
                         .map_err(|err| err.cancel())
-                    && self.token.kind == TokenKind::Colon
+                    && self.token == TokenKind::Colon
                 {
                     err.span_suggestion(
                         removal_span,
@@ -2367,12 +2367,12 @@ impl<'a> Parser<'a> {
         match self.expected_one_of_not_found(&[], expected) {
             Ok(error_guaranteed) => Ok(error_guaranteed),
             Err(mut err) => {
-                if self.token.kind == token::CloseDelim(Delimiter::Brace) {
+                if self.token == token::CloseDelim(Delimiter::Brace) {
                     // The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
                     // the AST for typechecking.
                     err.span_label(ident_span, "while parsing this `fn`");
                     Ok(err.emit())
-                } else if self.token.kind == token::RArrow
+                } else if self.token == token::RArrow
                     && let Some(fn_params_end) = fn_params_end
                 {
                     // Instead of a function body, the parser has encountered a right arrow
@@ -2445,7 +2445,7 @@ impl<'a> Parser<'a> {
         fn_params_end: Option<Span>,
     ) -> PResult<'a, Option<P<Block>>> {
         let has_semi = if req_body {
-            self.token.kind == TokenKind::Semi
+            self.token == TokenKind::Semi
         } else {
             // Only include `;` in list of expected tokens if body is not required
             self.check(&TokenKind::Semi)
@@ -2458,7 +2458,7 @@ impl<'a> Parser<'a> {
         } else if self.check(&token::OpenDelim(Delimiter::Brace)) || self.token.is_whole_block() {
             self.parse_block_common(self.token.span, BlockCheckMode::Default, false)
                 .map(|(attrs, body)| (attrs, Some(body)))?
-        } else if self.token.kind == token::Eq {
+        } else if self.token == token::Eq {
             // Recover `fn foo() = $expr;`.
             self.bump(); // `=`
             let eq_sp = self.prev_token.span;
@@ -2761,7 +2761,7 @@ impl<'a> Parser<'a> {
     pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec<Param>> {
         let mut first_param = true;
         // Parse the arguments, starting out with `self` being allowed...
-        if self.token.kind != TokenKind::OpenDelim(Delimiter::Parenthesis)
+        if self.token != TokenKind::OpenDelim(Delimiter::Parenthesis)
         // might be typo'd trait impl, handled elsewhere
         && !self.token.is_keyword(kw::For)
         {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 9b3b6d5f9ad..db74ea62790 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -527,7 +527,7 @@ impl<'a> Parser<'a> {
         } else if inedible.contains(&self.token.kind) {
             // leave it in the input
             Ok(Recovered::No)
-        } else if self.token.kind != token::Eof
+        } else if self.token != token::Eof
             && self.last_unexpected_token_span == Some(self.token.span)
         {
             FatalError.raise();
@@ -756,7 +756,7 @@ impl<'a> Parser<'a> {
     /// compound tokens like multi-character operators in process.
     /// Returns `true` if the token was eaten.
     fn break_and_eat(&mut self, expected: TokenKind) -> bool {
-        if self.token.kind == expected {
+        if self.token == expected {
             self.bump();
             return true;
         }
@@ -882,7 +882,7 @@ impl<'a> Parser<'a> {
                             let token_str = pprust::token_kind_to_string(t);
 
                             match self.current_closure.take() {
-                                Some(closure_spans) if self.token.kind == TokenKind::Semi => {
+                                Some(closure_spans) if self.token == TokenKind::Semi => {
                                     // Finding a semicolon instead of a comma
                                     // after a closure body indicates that the
                                     // closure body may be a block but the user
@@ -910,7 +910,7 @@ impl<'a> Parser<'a> {
                             // If this was a missing `@` in a binding pattern
                             // bail with a suggestion
                             // https://github.com/rust-lang/rust/issues/72373
-                            if self.prev_token.is_ident() && self.token.kind == token::DotDot {
+                            if self.prev_token.is_ident() && self.token == token::DotDot {
                                 let msg = format!(
                                     "if you meant to bind the contents of the rest of the array \
                                      pattern into `{}`, use `@`",
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 5bfb8bdf776..089da1ffaf4 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -369,7 +369,7 @@ impl<'a> Parser<'a> {
                     .and_then(|(ident, _)| ident.name.as_str().chars().next())
                     .is_some_and(char::is_lowercase)
             })
-            && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Parenthesis));
+            && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Parenthesis));
 
         // Check for operators.
         // `|` is excluded as it is used in pattern alternatives and lambdas,
@@ -377,9 +377,9 @@ impl<'a> Parser<'a> {
         // `[` is included for indexing operations,
         // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`)
         let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or)
-            || self.token.kind == token::Question
-            || (self.token.kind == token::OpenDelim(Delimiter::Bracket)
-                && self.look_ahead(1, |tok| tok.kind != token::CloseDelim(Delimiter::Bracket)));
+            || self.token == token::Question
+            || (self.token == token::OpenDelim(Delimiter::Bracket)
+                && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket)));
 
         if !has_trailing_method && !has_trailing_operator {
             // Nothing to recover here.
@@ -413,7 +413,7 @@ impl<'a> Parser<'a> {
                 let is_bound = is_end_bound
                     // is_start_bound: either `..` or `)..`
                     || self.token.is_range_separator()
-                    || self.token.kind == token::CloseDelim(Delimiter::Parenthesis)
+                    || self.token == token::CloseDelim(Delimiter::Parenthesis)
                         && self.look_ahead(1, Token::is_range_separator);
 
                 // Check that `parse_expr_assoc_with` didn't eat a rhs.
@@ -450,7 +450,7 @@ impl<'a> Parser<'a> {
             lo = self.token.span;
         }
 
-        let pat = if self.check(&token::BinOp(token::And)) || self.token.kind == token::AndAnd {
+        let pat = if self.check(&token::BinOp(token::And)) || self.token == token::AndAnd {
             self.parse_pat_deref(expected)?
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             self.parse_pat_tuple_or_parens()?
@@ -625,7 +625,7 @@ impl<'a> Parser<'a> {
     ///
     /// [and]: https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
     fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
-        if self.token.kind != token::At {
+        if self.token != token::At {
             // Next token is not `@` so it's not going to be an intersection pattern.
             return Ok(lhs);
         }
@@ -958,14 +958,14 @@ impl<'a> Parser<'a> {
         self.check_inline_const(dist)
             || self.look_ahead(dist, |t| {
                 t.is_path_start() // e.g. `MY_CONST`;
-                || t.kind == token::Dot // e.g. `.5` for recovery;
+                || *t == token::Dot // e.g. `.5` for recovery;
                 || matches!(t.kind, token::Literal(..) | token::BinOp(token::Minus))
                 || t.is_bool_lit()
                 || t.is_whole_expr()
                 || t.is_lifetime() // recover `'a` instead of `'a'`
                 || (self.may_recover() // recover leading `(`
-                    && t.kind == token::OpenDelim(Delimiter::Parenthesis)
-                    && self.look_ahead(dist + 1, |t| t.kind != token::OpenDelim(Delimiter::Parenthesis))
+                    && *t == token::OpenDelim(Delimiter::Parenthesis)
+                    && self.look_ahead(dist + 1, |t| *t != token::OpenDelim(Delimiter::Parenthesis))
                     && self.is_pat_range_end_start(dist + 1))
             })
     }
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 6f82d6b9826..007d760aba3 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -358,9 +358,9 @@ impl<'a> Parser<'a> {
                     })?;
                     let span = lo.to(self.prev_token.span);
                     AngleBracketedArgs { args, span }.into()
-                } else if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
+                } else if self.token == token::OpenDelim(Delimiter::Parenthesis)
                     // FIXME(return_type_notation): Could also recover `...` here.
-                    && self.look_ahead(1, |tok| tok.kind == token::DotDot)
+                    && self.look_ahead(1, |t| *t == token::DotDot)
                 {
                     self.bump(); // (
                     self.bump(); // ..
@@ -384,7 +384,7 @@ impl<'a> Parser<'a> {
                     let token_before_parsing = self.token.clone();
                     let mut snapshot = None;
                     if self.may_recover()
-                        && prev_token_before_parsing.kind == token::PathSep
+                        && prev_token_before_parsing == token::PathSep
                         && (style == PathStyle::Expr && self.token.can_begin_expr()
                             || style == PathStyle::Pat && self.token.can_begin_pattern())
                     {
@@ -393,7 +393,7 @@ impl<'a> Parser<'a> {
 
                     let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) {
                         Ok(output) => output,
-                        Err(mut error) if prev_token_before_parsing.kind == token::PathSep => {
+                        Err(mut error) if prev_token_before_parsing == token::PathSep => {
                             error.span_label(
                                 prev_token_before_parsing.span.to(token_before_parsing.span),
                                 "while parsing this parenthesized list of type arguments starting here",
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index b206f134f0e..c4fc0dfbaec 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -68,7 +68,7 @@ impl<'a> Parser<'a> {
             self.collect_tokens_trailing_token(attrs, force_collect, |this, attrs| {
                 this.expect_keyword(kw::Let)?;
                 let local = this.parse_local(attrs)?;
-                let trailing = capture_semi && this.token.kind == token::Semi;
+                let trailing = capture_semi && this.token == token::Semi;
                 Ok((this.mk_stmt(lo.to(this.prev_token.span), StmtKind::Let(local)), trailing))
             })?
         } else if self.is_kw_followed_by_ident(kw::Mut) && self.may_recover() {
@@ -760,7 +760,7 @@ impl<'a> Parser<'a> {
                                     )
                                 ),
                             );
-                            let suggest_eq = if self.token.kind == token::Dot
+                            let suggest_eq = if self.token == token::Dot
                                 && let _ = self.bump()
                                 && let mut snapshot = self.create_snapshot_for_diagnostic()
                                 && let Ok(_) = snapshot
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 352ddd9eac4..a8e8270673a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -420,7 +420,7 @@ impl<'a> Parser<'a> {
         let mut trailing_plus = false;
         let (ts, trailing) = self.parse_paren_comma_seq(|p| {
             let ty = p.parse_ty()?;
-            trailing_plus = p.prev_token.kind == TokenKind::BinOp(token::Plus);
+            trailing_plus = p.prev_token == TokenKind::BinOp(token::Plus);
             Ok(ty)
         })?;
 
@@ -499,8 +499,8 @@ impl<'a> Parser<'a> {
         let elt_ty = match self.parse_ty() {
             Ok(ty) => ty,
             Err(err)
-                if self.look_ahead(1, |t| t.kind == token::CloseDelim(Delimiter::Bracket))
-                    | self.look_ahead(1, |t| t.kind == token::Semi) =>
+                if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Bracket))
+                    | self.look_ahead(1, |t| *t == token::Semi) =>
             {
                 // Recover from `[LIT; EXPR]` and `[LIT]`
                 self.bump();
@@ -601,7 +601,7 @@ impl<'a> Parser<'a> {
         let span_start = self.token.span;
         let ast::FnHeader { ext, safety, constness, coroutine_kind } =
             self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
-        if self.may_recover() && self.token.kind == TokenKind::Lt {
+        if self.may_recover() && self.token == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
         }
         let decl = self.parse_fn_decl(|_| false, AllowPlus::No, recover_return_sign)?;
@@ -681,7 +681,7 @@ impl<'a> Parser<'a> {
         // Always parse bounds greedily for better error recovery.
         let bounds = self.parse_generic_bounds()?;
 
-        *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
+        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus);
 
         Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
     }
@@ -727,8 +727,7 @@ impl<'a> Parser<'a> {
         self.check_keyword(kw::Dyn)
             && (self.token.uninterpolated_span().at_least_rust_2018()
                 || self.look_ahead(1, |t| {
-                    (can_begin_dyn_bound_in_edition_2015(t)
-                        || t.kind == TokenKind::BinOp(token::Star))
+                    (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::BinOp(token::Star))
                         && !can_continue_type_after_non_fn_ident(t)
                 }))
     }
@@ -750,7 +749,7 @@ impl<'a> Parser<'a> {
 
         // Always parse bounds greedily for better error recovery.
         let bounds = self.parse_generic_bounds()?;
-        *impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
+        *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus);
         Ok(TyKind::TraitObject(bounds, syntax))
     }
 
@@ -1060,7 +1059,7 @@ impl<'a> Parser<'a> {
         }
 
         let mut path = if self.token.is_keyword(kw::Fn)
-            && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis))
+            && self.look_ahead(1, |t| *t == TokenKind::OpenDelim(Delimiter::Parenthesis))
             && let Some(path) = self.recover_path_from_fn()
         {
             path
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 672dddf871e..693867c3853 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1188,7 +1188,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     // Sanitizers can only be used on platforms that we know have working sanitizer codegen.
     let supported_sanitizers = sess.target.options.supported_sanitizers;
-    let unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+    let mut unsupported_sanitizers = sess.opts.unstable_opts.sanitizer - supported_sanitizers;
+    // Niche: if `fixed-x18`, or effectively switching on `reserved-x18` flag, is enabled
+    // we should allow Shadow Call Stack sanitizer.
+    if sess.opts.unstable_opts.fixed_x18 && sess.target.arch == "aarch64" {
+        unsupported_sanitizers -= SanitizerSet::SHADOWCALLSTACK;
+    }
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
deleted file mode 100644
index 656130cda19..00000000000
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-pub use rustc_middle::traits::query::type_op::Eq;
-use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
-
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
-
-impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
-    type QueryResponse = ();
-
-    fn try_fast_path(
-        _tcx: TyCtxt<'tcx>,
-        key: &ParamEnvAnd<'tcx, Eq<'tcx>>,
-    ) -> Option<Self::QueryResponse> {
-        if key.value.a == key.value.b { Some(()) } else { None }
-    }
-
-    fn perform_query(
-        tcx: TyCtxt<'tcx>,
-        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
-        tcx.type_op_eq(canonicalized)
-    }
-
-    fn perform_locally_with_next_solver(
-        ocx: &ObligationCtxt<'_, 'tcx>,
-        key: ParamEnvAnd<'tcx, Self>,
-    ) -> Result<Self::QueryResponse, NoSolution> {
-        ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?;
-        Ok(())
-    }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 2f64ed963f9..791424065d1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -16,12 +16,10 @@ use crate::traits::{ObligationCause, ObligationCtxt};
 
 pub mod ascribe_user_type;
 pub mod custom;
-pub mod eq;
 pub mod implied_outlives_bounds;
 pub mod normalize;
 pub mod outlives;
 pub mod prove_predicate;
-pub mod subtype;
 
 pub use rustc_middle::traits::query::type_op::*;
 
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
deleted file mode 100644
index 892c2a1f113..00000000000
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-pub use rustc_middle::traits::query::type_op::Subtype;
-use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
-
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
-
-impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
-    type QueryResponse = ();
-
-    fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> {
-        if key.value.sub == key.value.sup { Some(()) } else { None }
-    }
-
-    fn perform_query(
-        tcx: TyCtxt<'tcx>,
-        canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
-    ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
-        tcx.type_op_subtype(canonicalized)
-    }
-
-    fn perform_locally_with_next_solver(
-        ocx: &ObligationCtxt<'_, 'tcx>,
-        key: ParamEnvAnd<'tcx, Self>,
-    ) -> Result<Self::QueryResponse, NoSolution> {
-        ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?;
-        Ok(())
-    }
-}
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 5affadaac38..f34adf85755 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -10,18 +10,14 @@ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
     type_op_ascribe_user_type_with_span, AscribeUserType,
 };
-use rustc_trait_selection::traits::query::type_op::eq::Eq;
 use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
 use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
-use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
 use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
 
 pub(crate) fn provide(p: &mut Providers) {
     *p = Providers {
         type_op_ascribe_user_type,
-        type_op_eq,
         type_op_prove_predicate,
-        type_op_subtype,
         type_op_normalize_ty,
         type_op_normalize_clause,
         type_op_normalize_fn_sig,
@@ -39,16 +35,6 @@ fn type_op_ascribe_user_type<'tcx>(
     })
 }
 
-fn type_op_eq<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
-) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
-    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
-        let (param_env, Eq { a, b }) = key.into_parts();
-        Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?)
-    })
-}
-
 fn type_op_normalize<'tcx, T>(
     ocx: &ObligationCtxt<'_, 'tcx>,
     key: ParamEnvAnd<'tcx, Normalize<T>>,
@@ -91,16 +77,6 @@ fn type_op_normalize_poly_fn_sig<'tcx>(
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, type_op_normalize)
 }
 
-fn type_op_subtype<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>,
-) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
-    tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
-        let (param_env, Subtype { sub, sup }) = key.into_parts();
-        Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?)
-    })
-}
-
 fn type_op_prove_predicate<'tcx>(
     tcx: TyCtxt<'tcx>,
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index bfd0e42acfd..1e2e90105a9 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1056,11 +1056,29 @@ Executed at: {executed_at}"#,
             }
         };
 
-        let fail = |message: &str| {
+        let fail = |message: &str, output: CommandOutput| -> ! {
             if self.is_verbose() {
                 println!("{message}");
             } else {
-                println!("Command has failed. Rerun with -v to see more details.");
+                let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
+                // If the command captures output, the user would not see any indication that
+                // it has failed. In this case, print a more verbose error, since to provide more
+                // context.
+                if stdout.is_some() || stderr.is_some() {
+                    if let Some(stdout) =
+                        output.stdout_if_present().take_if(|s| !s.trim().is_empty())
+                    {
+                        println!("STDOUT:\n{stdout}\n");
+                    }
+                    if let Some(stderr) =
+                        output.stderr_if_present().take_if(|s| !s.trim().is_empty())
+                    {
+                        println!("STDERR:\n{stderr}\n");
+                    }
+                    println!("Command {command:?} has failed. Rerun with -v to see more details.");
+                } else {
+                    println!("Command has failed. Rerun with -v to see more details.");
+                }
             }
             exit!(1);
         };
@@ -1069,14 +1087,14 @@ Executed at: {executed_at}"#,
             match command.failure_behavior {
                 BehaviorOnFailure::DelayFail => {
                     if self.fail_fast {
-                        fail(&message);
+                        fail(&message, output);
                     }
 
                     let mut failures = self.delayed_failures.borrow_mut();
                     failures.push(message);
                 }
                 BehaviorOnFailure::Exit => {
-                    fail(&message);
+                    fail(&message, output);
                 }
                 BehaviorOnFailure::Ignore => {
                     // If failures are allowed, either the error has been printed already
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 9f0d0b7e969..530d760a584 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -292,6 +292,11 @@ impl CommandOutput {
     }
 
     #[must_use]
+    pub fn stdout_if_present(&self) -> Option<String> {
+        self.stdout.as_ref().and_then(|s| String::from_utf8(s.clone()).ok())
+    }
+
+    #[must_use]
     pub fn stdout_if_ok(&self) -> Option<String> {
         if self.is_success() { Some(self.stdout()) } else { None }
     }
@@ -303,6 +308,11 @@ impl CommandOutput {
         )
         .expect("Cannot parse process stderr as UTF-8")
     }
+
+    #[must_use]
+    pub fn stderr_if_present(&self) -> Option<String> {
+        self.stderr.as_ref().and_then(|s| String::from_utf8(s.clone()).ok())
+    }
 }
 
 impl Default for CommandOutput {
diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md
index 9ddf00e3a50..96499b0d801 100644
--- a/src/doc/rustc/src/platform-support/android.md
+++ b/src/doc/rustc/src/platform-support/android.md
@@ -61,3 +61,8 @@ Currently the `riscv64-linux-android` target requires the following architecture
 * `Zba` (address calculation instructions)
 * `Zbb` (base instructions)
 * `Zbs` (single-bit instructions)
+
+### aarch64-linux-android on Nightly compilers
+
+As soon as `-Zfixed-x18` compiler flag is supplied, the [`ShadowCallStack` sanitizer](https://releases.llvm.org/7.0.1/tools/clang/docs/ShadowCallStack.html)
+instrumentation is also made avaiable by supplying the second compiler flag `-Zsanitizer=shadow-call-stack`.
diff --git a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
index 8c8bff5fa29..b215bc84fbb 100644
--- a/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
+++ b/src/doc/unstable-book/src/compiler-flags/fixed-x18.md
@@ -1,7 +1,7 @@
 # `fixed-x18`
 
 This option prevents the compiler from using the x18 register. It is only
-supported on aarch64.
+supported on `aarch64`.
 
 From the [ABI spec][arm-abi]:
 
@@ -23,6 +23,11 @@ Currently, the `-Zsanitizer=shadow-call-stack` flag is only supported on
 platforms that always treat x18 as a reserved register, and the `-Zfixed-x18`
 flag is not required to use the sanitizer on such platforms. However, the
 sanitizer may be supported on targets where this is not the case in the future.
+One way to do so now on Nightly compilers is to explicitly supply this `-Zfixed-x18`
+flag with `aarch64` targets, so that the sanitizer is available for instrumentation
+on targets like `aarch64-unknown-none`, for instance. However, discretion is still
+required to make sure that the runtime support is in place for this sanitizer
+to be effective.
 
 It is undefined behavior for `-Zsanitizer=shadow-call-stack` code to call into
 code where x18 is a temporary register. On the other hand, when you are *not*
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 72b44e002b4..edc63a25ac1 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -787,6 +787,10 @@ A runtime must be provided by the application or operating system.
 
 See the [Clang ShadowCallStack documentation][clang-scs] for more details.
 
+* `aarch64-unknown-none`
+
+In addition to support from a runtime by the application or operating system, the `-Zfixed-x18` flag is also mandatory.
+
 # ThreadSanitizer
 
 ThreadSanitizer is a data race detection tool. It is supported on the following
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 860672443f2..a424faaf999 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -13,12 +13,15 @@ use std::io::{stdout, BufWriter, Write};
 use std::path::PathBuf;
 use std::rc::Rc;
 
-use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustdoc_json_types as types;
+// It's important to use the FxHashMap from rustdoc_json_types here, instead of
+// the one from rustc_data_structures, as they're different types due to sysroots.
+// See #110051 and #127456 for details
+use rustdoc_json_types::FxHashMap;
 
 use crate::clean::types::{ExternalCrate, ExternalLocation};
 use crate::clean::ItemKind;
@@ -234,14 +237,11 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
         let index = (*self.index).clone().into_inner();
 
         debug!("Constructing Output");
-        // This needs to be the default HashMap for compatibility with the public interface for
-        // rustdoc-json-types
-        #[allow(rustc::default_hash_types)]
         let output = types::Crate {
             root: types::Id(format!("0:0:{}", e.name(self.tcx).as_u32())),
             crate_version: self.cache.crate_version.clone(),
             includes_private: self.cache.document_private,
-            index: index.into_iter().collect(),
+            index,
             paths: self
                 .cache
                 .paths
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 999134a4090..40a90c1a565 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -5,7 +5,7 @@
 
 use std::path::PathBuf;
 
-use rustc_hash::FxHashMap;
+pub use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 
 /// The version of JSON output that this crate represents.
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index de91233d196..87117832fb9 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -470,7 +470,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
     });
 
     // Find both the last lint declaration (declare_clippy_lint!) and the lint pass impl
-    while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token_kind == TokenKind::Ident) {
+    while let Some(LintDeclSearchResult { content, .. }) = iter.find(|result| result.token == TokenKind::Ident) {
         let mut iter = iter
             .by_ref()
             .filter(|t| !matches!(t.token_kind, TokenKind::Whitespace | TokenKind::LineComment { .. }));
@@ -480,7 +480,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
                 // matches `!{`
                 match_tokens!(iter, Bang OpenBrace);
                 if let Some(LintDeclSearchResult { range, .. }) =
-                    iter.find(|result| result.token_kind == TokenKind::CloseBrace)
+                    iter.find(|result| result.token == TokenKind::CloseBrace)
                 {
                     last_decl_curly_offset = Some(range.end);
                 }
diff --git a/src/tools/run-make-support/src/external_deps/rustdoc.rs b/src/tools/run-make-support/src/external_deps/rustdoc.rs
index 96c2218a563..96b1c719e2e 100644
--- a/src/tools/run-make-support/src/external_deps/rustdoc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs
@@ -71,14 +71,8 @@ impl Rustdoc {
         self
     }
 
-    /// Specify path to the output folder.
-    pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
-        self.cmd.arg("-o");
-        self.cmd.arg(path.as_ref());
-        self
-    }
-
     /// Specify output directory.
+    #[doc(alias = "output")]
     pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
         self.cmd.arg("--out-dir").arg(path.as_ref());
         self
diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 60c827fd03b..8d5f7f90958 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -84,9 +84,7 @@ pub(crate) struct ParsedMacroArgs {
 fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
     for &keyword in RUST_KW.iter() {
         if parser.token.is_keyword(keyword)
-            && parser.look_ahead(1, |t| {
-                t.kind == TokenKind::Eof || t.kind == TokenKind::Comma
-            })
+            && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma)
         {
             parser.bump();
             return Some(MacroArg::Keyword(
@@ -131,7 +129,7 @@ pub(crate) fn parse_macro_args(
                                 Some(arg) => {
                                     args.push(arg);
                                     parser.bump();
-                                    if parser.token.kind == TokenKind::Eof && args.len() == 2 {
+                                    if parser.token == TokenKind::Eof && args.len() == 2 {
                                         vec_with_semi = true;
                                         break;
                                     }
@@ -150,7 +148,7 @@ pub(crate) fn parse_macro_args(
 
             parser.bump();
 
-            if parser.token.kind == TokenKind::Eof {
+            if parser.token == TokenKind::Eof {
                 trailing_comma = true;
                 break;
             }
diff --git a/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
new file mode 100644
index 00000000000..e2e14ab14a8
--- /dev/null
+++ b/tests/codegen/sanitizer/aarch64-shadow-call-stack-with-fixed-x18.rs
@@ -0,0 +1,19 @@
+//@ revisions: aarch64 android
+//@[aarch64] compile-flags: --target aarch64-unknown-none -Zfixed-x18 -Zsanitizer=shadow-call-stack
+//@[aarch64] needs-llvm-components: aarch64
+//@[android] compile-flags: --target aarch64-linux-android -Zsanitizer=shadow-call-stack
+//@[android] needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+// CHECK: ; Function Attrs:{{.*}}shadowcallstack
+#[no_mangle]
+pub fn foo() {}
+
+// CHECK: attributes #0 = {{.*}}shadowcallstack{{.*}}
diff --git a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
index 91fc0a9025f..0ad5934f62e 100644
--- a/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
+++ b/tests/run-make/deref-impl-rustdoc-ice/rmake.rs
@@ -12,5 +12,5 @@ use run_make_support::{cwd, rustc, rustdoc};
 fn main() {
     rustc().input("foo.rs").run();
     rustc().input("bar.rs").run();
-    rustdoc().input("baz.rs").library_search_path(cwd()).output(cwd()).run();
+    rustdoc().input("baz.rs").library_search_path(cwd()).out_dir(cwd()).run();
 }
diff --git a/tests/run-make/emit-shared-files/rmake.rs b/tests/run-make/emit-shared-files/rmake.rs
index 8ac9073e993..e5482af10bb 100644
--- a/tests/run-make/emit-shared-files/rmake.rs
+++ b/tests/run-make/emit-shared-files/rmake.rs
@@ -13,7 +13,7 @@ fn main() {
     rustdoc()
         .arg("-Zunstable-options")
         .arg("--emit=invocation-specific")
-        .output("invocation-only")
+        .out_dir("invocation-only")
         .arg("--resource-suffix=-xxx")
         .args(&["--theme", "y.css"])
         .args(&["--extend-css", "z.css"])
@@ -34,7 +34,7 @@ fn main() {
     rustdoc()
         .arg("-Zunstable-options")
         .arg("--emit=toolchain-shared-resources")
-        .output("toolchain-only")
+        .out_dir("toolchain-only")
         .arg("--resource-suffix=-xxx")
         .args(&["--extend-css", "z.css"])
         .input("x.rs")
@@ -68,7 +68,7 @@ fn main() {
     rustdoc()
         .arg("-Zunstable-options")
         .arg("--emit=toolchain-shared-resources,unversioned-shared-resources")
-        .output("all-shared")
+        .out_dir("all-shared")
         .arg("--resource-suffix=-xxx")
         .args(&["--extend-css", "z.css"])
         .input("x.rs")
diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs
index f290554831d..d3dcc04428c 100644
--- a/tests/run-make/exit-code/rmake.rs
+++ b/tests/run-make/exit-code/rmake.rs
@@ -16,7 +16,7 @@ fn main() {
         .run_fail()
         .assert_exit_code(101);
 
-    rustdoc().arg("success.rs").output("exit-code").run();
+    rustdoc().arg("success.rs").out_dir("exit-code").run();
 
     rustdoc().arg("--invalid-arg-foo").run_fail().assert_exit_code(1);
 
diff --git a/tests/run-make/rustdoc-determinism/rmake.rs b/tests/run-make/rustdoc-determinism/rmake.rs
index aa8090174d9..ce088508178 100644
--- a/tests/run-make/rustdoc-determinism/rmake.rs
+++ b/tests/run-make/rustdoc-determinism/rmake.rs
@@ -7,12 +7,12 @@ use run_make_support::{diff, rustdoc};
 
 fn main() {
     let foo_first = Path::new("foo_first");
-    rustdoc().input("foo.rs").output(&foo_first).run();
-    rustdoc().input("bar.rs").output(&foo_first).run();
+    rustdoc().input("foo.rs").out_dir(&foo_first).run();
+    rustdoc().input("bar.rs").out_dir(&foo_first).run();
 
     let bar_first = Path::new("bar_first");
-    rustdoc().input("bar.rs").output(&bar_first).run();
-    rustdoc().input("foo.rs").output(&bar_first).run();
+    rustdoc().input("bar.rs").out_dir(&bar_first).run();
+    rustdoc().input("foo.rs").out_dir(&bar_first).run();
 
     diff()
         .expected_file(foo_first.join("search-index.js"))
diff --git a/tests/run-make/rustdoc-io-error/rmake.rs b/tests/run-make/rustdoc-io-error/rmake.rs
index a5fae36e733..31441d7ebc5 100644
--- a/tests/run-make/rustdoc-io-error/rmake.rs
+++ b/tests/run-make/rustdoc-io-error/rmake.rs
@@ -25,7 +25,7 @@ fn main() {
     permissions.set_readonly(true);
     rfs::set_permissions(&out_dir, permissions);
 
-    let output = rustdoc().input("foo.rs").output(&out_dir).env("RUST_BACKTRACE", "1").run_fail();
+    let output = rustdoc().input("foo.rs").out_dir(&out_dir).env("RUST_BACKTRACE", "1").run_fail();
 
     rfs::set_permissions(&out_dir, original_permissions);
 
diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs
index 08f9595ef9f..a4485165fd2 100644
--- a/tests/run-make/rustdoc-map-file/rmake.rs
+++ b/tests/run-make/rustdoc-map-file/rmake.rs
@@ -6,7 +6,7 @@ fn main() {
         .input("foo.rs")
         .arg("-Zunstable-options")
         .arg("--generate-redirect-map")
-        .output(&out_dir)
+        .out_dir(&out_dir)
         .run();
     // FIXME (GuillaumeGomez): Port the python script to Rust as well.
     python_command().arg("validate_json.py").arg(&out_dir).run();
diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs
index 3c1ccd3a069..181239eac4d 100644
--- a/tests/run-make/rustdoc-output-path/rmake.rs
+++ b/tests/run-make/rustdoc-output-path/rmake.rs
@@ -6,6 +6,6 @@ use run_make_support::rustdoc;
 
 fn main() {
     let out_dir = Path::new("foo/bar/doc");
-    rustdoc().input("foo.rs").output(&out_dir).run();
+    rustdoc().input("foo.rs").out_dir(&out_dir).run();
     assert!(out_dir.exists());
 }
diff --git a/tests/run-make/rustdoc-output-stdout/rmake.rs b/tests/run-make/rustdoc-output-stdout/rmake.rs
index e7dfb66602c..dbc9892f3f5 100644
--- a/tests/run-make/rustdoc-output-stdout/rmake.rs
+++ b/tests/run-make/rustdoc-output-stdout/rmake.rs
@@ -10,7 +10,7 @@ fn main() {
     // First we check that we generate the JSON in the stdout.
     rustdoc()
         .input("foo.rs")
-        .output("-")
+        .out_dir("-")
         .arg("-Zunstable-options")
         .output_format("json")
         .run()
diff --git a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
index b77df7adc8d..546a0685b4e 100644
--- a/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-macros/rmake.rs
@@ -35,7 +35,7 @@ fn main() {
         .input("examples/ex.rs")
         .crate_name("ex")
         .crate_type("bin")
-        .output(&out_dir)
+        .out_dir(&out_dir)
         .extern_(crate_name, rust_lib_name(crate_name))
         .extern_(proc_crate_name, dylib_name.trim())
         .arg("-Zunstable-options")
@@ -49,7 +49,7 @@ fn main() {
         .input("src/lib.rs")
         .crate_name(crate_name)
         .crate_type("lib")
-        .output(&out_dir)
+        .out_dir(&out_dir)
         .arg("-Zunstable-options")
         .arg("--with-examples")
         .arg(&ex_dir)
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
index eca07043b55..c4d7814c3c8 100644
--- a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
+++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
@@ -20,7 +20,7 @@ pub fn scrape(extra_args: &[&str]) {
             .input(&dep)
             .crate_name(&dep_stem)
             .crate_type("bin")
-            .output(&out_dir)
+            .out_dir(&out_dir)
             .extern_(crate_name, format!("lib{crate_name}.rmeta"))
             .arg("-Zunstable-options")
             .arg("--scrape-examples-output-path")
@@ -35,7 +35,7 @@ pub fn scrape(extra_args: &[&str]) {
     let mut rustdoc = rustdoc();
     rustdoc
         .input("src/lib.rs")
-        .output(&out_dir)
+        .out_dir(&out_dir)
         .crate_name(crate_name)
         .crate_type("lib")
         .arg("-Zunstable-options");
diff --git a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
index 3246fc56506..fe9587f5022 100644
--- a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
+++ b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
@@ -7,7 +7,7 @@ fn main() {
     rustc().crate_type("lib").input("dummy_core.rs").target("target.json").run();
     rustdoc()
         .input("my_crate.rs")
-        .output(out_dir)
+        .out_dir(out_dir)
         .library_search_path(cwd())
         .target("target.json")
         .run();
diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs
index 8a961beb9f7..4577e47d47e 100644
--- a/tests/run-make/rustdoc-themes/rmake.rs
+++ b/tests/run-make/rustdoc-themes/rmake.rs
@@ -27,6 +27,6 @@ fn main() {
     rfs::create_dir_all(&out_dir);
     rfs::write(&test_css, test_content);
 
-    rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
+    rustdoc().out_dir(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
     htmldocck().arg(out_dir).arg("foo.rs").run();
 }
diff --git a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
index ded89c9ae79..a82a1965a9c 100644
--- a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
+++ b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
@@ -2,6 +2,6 @@ use run_make_support::{htmldocck, rustdoc};
 
 fn main() {
     let out_dir = "rustdoc";
-    rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
+    rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").out_dir(&out_dir).run();
     htmldocck().arg(out_dir).arg("src/lib.rs").run();
 }
diff --git a/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
new file mode 100644
index 00000000000..d758c903087
--- /dev/null
+++ b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: --target aarch64-unknown-none -Zsanitizer=shadow-call-stack
+//@ error-pattern: shadow-call-stack sanitizer is not supported for this target
+//@ dont-check-compiler-stderr
+//@ needs-llvm-components: aarch64
+
+#![allow(internal_features)]
+#![crate_type = "rlib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {}
diff --git a/tests/ui/async-await/async-closures/move-out-of-ref.rs b/tests/ui/async-await/async-closures/move-out-of-ref.rs
new file mode 100644
index 00000000000..a05447232f6
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-out-of-ref.rs
@@ -0,0 +1,16 @@
+//@ compile-flags: -Zvalidate-mir
+//@ edition: 2021
+
+#![feature(async_closure)]
+
+// NOT copy.
+struct Ty;
+
+fn hello(x: &Ty) {
+    let c = async || {
+        *x;
+        //~^ ERROR cannot move out of `*x` which is behind a shared reference
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/move-out-of-ref.stderr b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
new file mode 100644
index 00000000000..294905a481d
--- /dev/null
+++ b/tests/ui/async-await/async-closures/move-out-of-ref.stderr
@@ -0,0 +1,18 @@
+error[E0507]: cannot move out of `*x` which is behind a shared reference
+  --> $DIR/move-out-of-ref.rs:11:9
+   |
+LL |         *x;
+   |         ^^ move occurs because `*x` has type `Ty`, which does not implement the `Copy` trait
+   |
+note: if `Ty` implemented `Clone`, you could clone the value
+  --> $DIR/move-out-of-ref.rs:7:1
+   |
+LL | struct Ty;
+   | ^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |         *x;
+   |         -- you could clone this value
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/async-await/async-closures/sig-from-bare-fn.rs b/tests/ui/async-await/async-closures/sig-from-bare-fn.rs
new file mode 100644
index 00000000000..a679471a3b3
--- /dev/null
+++ b/tests/ui/async-await/async-closures/sig-from-bare-fn.rs
@@ -0,0 +1,49 @@
+//@ check-pass
+//@ edition: 2021
+
+// Make sure that we infer the args of an async closure even if it's passed to
+// a function that requires the async closure implement `Fn*` but does *not* have
+// a `Future` bound on the return type.
+
+#![feature(async_closure)]
+
+use std::future::Future;
+
+trait TryStream {
+    type Ok;
+    type Err;
+}
+
+trait TryFuture {
+    type Ok;
+    type Err;
+}
+
+impl<F, T, E> TryFuture for F where F: Future<Output = Result<T, E>> {
+    type Ok = T;
+    type Err = E;
+}
+
+trait TryStreamExt: TryStream {
+    fn try_for_each<F, Fut>(&self, f: F)
+    where
+        F: FnMut(Self::Ok) -> Fut,
+        Fut: TryFuture<Ok = (), Err = Self::Err>;
+}
+
+impl<S> TryStreamExt for S where S: TryStream {
+    fn try_for_each<F, Fut>(&self, f: F)
+    where
+        F: FnMut(Self::Ok) -> Fut,
+        Fut: TryFuture<Ok = (), Err = Self::Err>,
+    { }
+}
+
+fn test(stream: impl TryStream<Ok = &'static str, Err = ()>) {
+    stream.try_for_each(async |s| {
+        s.trim(); // Make sure we know the type of `s` at this point.
+        Ok(())
+    });
+}
+
+fn main() {}