about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--compiler/rustc_ast/src/ast.rs7
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs1
-rw-r--r--compiler/rustc_ast/src/token.rs6
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs13
-rw-r--r--compiler/rustc_ast/src/visit.rs5
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs3
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs10
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs6
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs7
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs17
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs31
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs6
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_interface/src/interface.rs55
-rw-r--r--compiler/rustc_interface/src/tests.rs5
-rw-r--r--compiler/rustc_lint/src/unused.rs2
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs12
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs18
-rw-r--r--compiler/rustc_middle/src/macros.rs28
-rw-r--r--compiler/rustc_middle/src/thir.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs2
-rw-r--r--compiler/rustc_parse/messages.ftl2
-rw-r--r--compiler/rustc_parse/src/errors.rs7
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs47
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs10
-rw-r--r--compiler/rustc_parse/src/parser/item.rs14
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs36
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs15
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs22
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs20
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs2
-rw-r--r--compiler/rustc_passes/src/dead.rs4
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs2
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_pattern_analysis/Cargo.toml4
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs75
-rw-r--r--compiler/rustc_pattern_analysis/src/lib.rs9
-rw-r--r--compiler/rustc_pattern_analysis/src/pat.rs80
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs7
-rw-r--r--compiler/rustc_pattern_analysis/src/usefulness.rs25
-rw-r--r--compiler/rustc_pattern_analysis/tests/common/mod.rs315
-rw-r--r--compiler/rustc_pattern_analysis/tests/complexity.rs109
-rw-r--r--compiler/rustc_pattern_analysis/tests/exhaustiveness.rs77
-rw-r--r--compiler/rustc_pattern_analysis/tests/intersection.rs69
-rw-r--r--compiler/rustc_privacy/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs7
-rw-r--r--compiler/rustc_session/src/config.rs45
-rw-r--r--compiler/rustc_session/src/session.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs2
-rw-r--r--compiler/rustc_target/src/spec/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/messages.ftl9
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs189
-rw-r--r--library/core/src/macros/mod.rs12
-rw-r--r--library/core/src/prelude/v1.rs8
-rw-r--r--library/std/src/prelude/v1.rs9
-rw-r--r--src/librustdoc/clean/utils.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/rustfmt/src/patterns.rs8
-rw-r--r--tests/run-make-fulldeps/obtain-borrowck/driver.rs2
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs45
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr193
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.rs12
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.stderr25
-rw-r--r--tests/ui/pattern/deref-patterns/typeck.rs8
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden4.rs25
-rw-r--r--tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr34
-rw-r--r--tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr6
83 files changed, 1480 insertions, 422 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3110f32ade9..0b9eb88ec2b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4440,6 +4440,8 @@ dependencies = [
  "rustc_target",
  "smallvec",
  "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
 ]
 
 [[package]]
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index d0e8b86b71d..e4096e244e1 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -621,7 +621,9 @@ impl Pat {
             | PatKind::Or(s) => s.iter().for_each(|p| p.walk(it)),
 
             // Trivial wrappers over inner patterns.
-            PatKind::Box(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => s.walk(it),
+            PatKind::Box(s) | PatKind::Deref(s) | PatKind::Ref(s, _) | PatKind::Paren(s) => {
+                s.walk(it)
+            }
 
             // These patterns do not contain subpatterns, skip.
             PatKind::Wild
@@ -792,6 +794,9 @@ pub enum PatKind {
     /// A `box` pattern.
     Box(P<Pat>),
 
+    /// A `deref` pattern (currently `deref!()` macro-based syntax).
+    Deref(P<Pat>),
+
     /// A reference pattern (e.g., `&mut (a, b)`).
     Ref(P<Pat>, Mutability),
 
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 83468c5f101..5b22ae5f54b 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1295,6 +1295,7 @@ pub fn noop_visit_pat<T: MutVisitor>(pat: &mut P<Pat>, vis: &mut T) {
             fields.flat_map_in_place(|field| vis.flat_map_pat_field(field));
         }
         PatKind::Box(inner) => vis.visit_pat(inner),
+        PatKind::Deref(inner) => vis.visit_pat(inner),
         PatKind::Ref(inner, _mutbl) => vis.visit_pat(inner),
         PatKind::Range(e1, e2, Spanned { span: _, node: _ }) => {
             visit_opt(e1, |e| vis.visit_expr(e));
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index c17020ed663..f49eb2f22c5 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -105,7 +105,7 @@ impl Lit {
         }
     }
 
-    /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
+    /// Keep this in sync with `Token::can_begin_literal_maybe_minus` excluding unary negation.
     pub fn from_token(token: &Token) -> Option<Lit> {
         match token.uninterpolate().kind {
             Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
@@ -664,7 +664,7 @@ impl Token {
     }
 
     /// Returns `true` if the token is an interpolated path.
-    fn is_path(&self) -> bool {
+    fn is_whole_path(&self) -> bool {
         if let Interpolated(nt) = &self.kind
             && let NtPath(..) = &nt.0
         {
@@ -710,7 +710,7 @@ impl Token {
     pub fn is_path_start(&self) -> bool {
         self == &ModSep
             || self.is_qpath_start()
-            || self.is_path()
+            || self.is_whole_path()
             || self.is_path_segment_keyword()
             || self.is_ident() && !self.is_reserved_ident()
     }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index adc3056cc29..239735456ad 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -28,18 +28,7 @@ use smallvec::{smallvec, SmallVec};
 use std::borrow::Cow;
 use std::{cmp, fmt, iter};
 
-/// When the main Rust parser encounters a syntax-extension invocation, it
-/// parses the arguments to the invocation as a token tree. This is a very
-/// loose structure, such that all sorts of different AST fragments can
-/// be passed to syntax extensions using a uniform type.
-///
-/// If the syntax extension is an MBE macro, it will attempt to match its
-/// LHS token tree against the provided token tree, and if it finds a
-/// match, will transcribe the RHS token tree, splicing in any captured
-/// `macro_parser::matched_nonterminals` into the `SubstNt`s it finds.
-///
-/// The RHS of an MBE macro is the only place `SubstNt`s are substituted.
-/// Nothing special happens to misnamed or misplaced `SubstNt`s.
+/// Part of a `TokenStream`.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
 pub enum TokenTree {
     /// A single token. Should never be `OpenDelim` or `CloseDelim`, because
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 825f8dad8e4..7bdbf48a81f 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -576,7 +576,10 @@ pub fn walk_pat<'a, V: Visitor<'a>>(visitor: &mut V, pattern: &'a Pat) -> V::Res
             try_visit!(visitor.visit_path(path, pattern.id));
             walk_list!(visitor, visit_pat_field, fields);
         }
-        PatKind::Box(subpattern) | PatKind::Ref(subpattern, _) | PatKind::Paren(subpattern) => {
+        PatKind::Box(subpattern)
+        | PatKind::Deref(subpattern)
+        | PatKind::Ref(subpattern, _)
+        | PatKind::Paren(subpattern) => {
             try_visit!(visitor.visit_pat(subpattern));
         }
         PatKind::Ident(_, ident, optional_subpattern) => {
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 469cdac11e4..8631d90be81 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -91,6 +91,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     PatKind::Box(inner) => {
                         break hir::PatKind::Box(self.lower_pat(inner));
                     }
+                    PatKind::Deref(inner) => {
+                        break hir::PatKind::Deref(self.lower_pat(inner));
+                    }
                     PatKind::Ref(inner, mutbl) => {
                         break hir::PatKind::Ref(self.lower_pat(inner), *mutbl);
                     }
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 277e82b4e53..81065fa3dce 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -413,10 +413,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
             PatKind::Box(..) => {
-                if !self.features.deref_patterns {
-                    // Allow box patterns under `deref_patterns`.
-                    gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
-                }
+                gate!(&self, box_patterns, pattern.span, "box pattern syntax is experimental");
             }
             PatKind::Range(_, Some(_), Spanned { node: RangeEnd::Excluded, .. }) => {
                 gate!(
@@ -610,10 +607,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
         };
     }
 
-    if !visitor.features.deref_patterns {
-        // Allow box patterns under `deref_patterns`.
-        gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
-    }
+    gate_all_legacy_dont_use!(box_patterns, "box pattern syntax is experimental");
     gate_all_legacy_dont_use!(trait_alias, "trait aliases are experimental");
     // Despite being a new feature, `where T: Trait<Assoc(): Sized>`, which is RTN syntax now,
     // used to be gated under associated_type_bounds, which are right above, so RTN needs to
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index c50878e32a4..a70daf1b644 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1626,6 +1626,12 @@ impl<'a> State<'a> {
                 self.word("box ");
                 self.print_pat(inner);
             }
+            PatKind::Deref(inner) => {
+                self.word("deref!");
+                self.popen();
+                self.print_pat(inner);
+                self.pclose();
+            }
             PatKind::Ref(inner, mutbl) => {
                 self.word("&");
                 if mutbl.is_mut() {
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 193b6d3e3d9..d5875a226fe 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -192,6 +192,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                         .find(|ur_vid| self.eval_equal(vid, **ur_vid))
                         .and_then(|ur_vid| self.definitions[*ur_vid].external_name)
                         .unwrap_or(infcx.tcx.lifetimes.re_erased),
+                    ty::RePlaceholder(_) => ty::Region::new_error_with_message(
+                        infcx.tcx,
+                        concrete_type.span,
+                        "hidden type contains placeholders, we don't support higher kinded opaques yet",
+                    ),
                     _ => region,
                 });
             debug!(?universal_concrete_type);
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index e6d42c596d2..e8b9490d401 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -21,7 +21,6 @@ use rustc_session::{
 };
 use rustc_span::symbol::Symbol;
 use rustc_target::abi::call::FnAbi;
-use rustc_target::spec::Target;
 
 use std::fmt;
 
@@ -70,12 +69,6 @@ pub trait CodegenBackend {
     fn print_passes(&self) {}
     fn print_version(&self) {}
 
-    /// If this plugin provides additional builtin targets, provide the one enabled by the options here.
-    /// Be careful: this is called *before* init() is called.
-    fn target_override(&self, _opts: &config::Options) -> Option<Target> {
-        None
-    }
-
     /// The metadata loader used to load rlib and dylib metadata.
     ///
     /// Alternative codegen backends may want to use different rlib or dylib formats than the
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 938f9f0beaa..716e31080dd 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -890,7 +890,7 @@ pub fn version_at_macro_invocation(
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
         let opts = config::Options::default();
         let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
+        let target = config::build_target_config(early_dcx, &opts, &sysroot);
 
         get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version();
     }
@@ -1100,7 +1100,7 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) ->
 
         let opts = config::Options::default();
         let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone());
-        let target = config::build_target_config(early_dcx, &opts, None, &sysroot);
+        let target = config::build_target_config(early_dcx, &opts, &sysroot);
 
         get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes();
         return true;
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ac5136539c3..a31be05ccc4 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -392,12 +392,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize {
 #[derive(Debug, Clone)]
 pub(crate) enum NamedMatch {
     MatchedSeq(Vec<NamedMatch>),
-
-    // A metavar match of type `tt`.
-    MatchedTokenTree(rustc_ast::tokenstream::TokenTree),
-
-    // A metavar match of any type other than `tt`.
-    MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>),
+    MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
 }
 
 /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@@ -691,11 +686,11 @@ impl TtParser {
                             }
                             Ok(nt) => nt,
                         };
-                        let m = match nt {
-                            ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))),
-                            ParseNtResult::Tt(tt) => MatchedTokenTree(tt),
-                        };
-                        mp.push_match(next_metavar, seq_depth, m);
+                        mp.push_match(
+                            next_metavar,
+                            seq_depth,
+                            MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
+                        );
                         mp.idx += 1;
                     } else {
                         unreachable!()
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 3f29d7f7465..7099f1b0d35 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -5,7 +5,7 @@ use crate::mbe;
 use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
 use crate::mbe::macro_check;
 use crate::mbe::macro_parser::{Error, ErrorReported, Failure, Success, TtParser};
-use crate::mbe::macro_parser::{MatchedSeq, MatchedTokenTree, MatcherLoc};
+use crate::mbe::macro_parser::{MatcherLoc, NamedMatch::*};
 use crate::mbe::transcribe::transcribe;
 
 use ast::token::IdentIsRaw;
@@ -22,7 +22,7 @@ use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
 };
 use rustc_lint_defs::BuiltinLintDiag;
-use rustc_parse::parser::{Parser, Recovery};
+use rustc_parse::parser::{ParseNtResult, Parser, Recovery};
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::edition::Edition;
@@ -479,7 +479,7 @@ pub fn compile_declarative_macro(
         MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(tt) = m {
+                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
                     let tt = mbe::quoted::parse(
                         &TokenStream::new(vec![tt.clone()]),
                         true,
@@ -505,7 +505,7 @@ pub fn compile_declarative_macro(
         MatchedSeq(s) => s
             .iter()
             .map(|m| {
-                if let MatchedTokenTree(tt) = m {
+                if let MatchedSingle(ParseNtResult::Tt(tt)) = m {
                     return mbe::quoted::parse(
                         &TokenStream::new(vec![tt.clone()]),
                         false,
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 8fcd468e34b..dad83984c8b 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -3,14 +3,14 @@ use crate::errors::{
     CountRepetitionMisplaced, MetaVarExprUnrecognizedVar, MetaVarsDifSeqMatchers, MustRepeatOnce,
     NoSyntaxVarsExprRepeat, VarStillRepeating,
 };
-use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree, NamedMatch};
+use crate::mbe::macro_parser::{NamedMatch, NamedMatch::*};
 use crate::mbe::{self, KleeneOp, MetaVarExpr};
 use rustc_ast::mut_visit::{self, MutVisitor};
 use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Diag;
-use rustc_errors::{pluralize, PResult};
+use rustc_errors::{pluralize, Diag, PResult};
+use rustc_parse::parser::ParseNtResult;
 use rustc_span::hygiene::{LocalExpnId, Transparency};
 use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
 use rustc_span::{with_metavar_spans, Span, SyntaxContext};
@@ -250,26 +250,25 @@ pub(super) fn transcribe<'a>(
                 // the meta-var.
                 let ident = MacroRulesNormalizedIdent::new(original_ident);
                 if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) {
-                    match cur_matched {
-                        MatchedTokenTree(tt) => {
+                    let tt = match cur_matched {
+                        MatchedSingle(ParseNtResult::Tt(tt)) => {
                             // `tt`s are emitted into the output stream directly as "raw tokens",
                             // without wrapping them into groups.
-                            let tt = maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker);
-                            result.push(tt);
+                            maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
                         }
-                        MatchedNonterminal(nt) => {
+                        MatchedSingle(ParseNtResult::Nt(nt)) => {
                             // Other variables are emitted into the output stream as groups with
                             // `Delimiter::Invisible` to maintain parsing priorities.
                             // `Interpolated` is currently used for such groups in rustc parser.
                             marker.visit_span(&mut sp);
-                            result
-                                .push(TokenTree::token_alone(token::Interpolated(nt.clone()), sp));
+                            TokenTree::token_alone(token::Interpolated(nt.clone()), sp)
                         }
                         MatchedSeq(..) => {
                             // We were unable to descend far enough. This is an error.
                             return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident }));
                         }
-                    }
+                    };
+                    result.push(tt)
                 } else {
                     // If we aren't able to match the meta-var, we push it back into the result but
                     // with modified syntax context. (I believe this supports nested macros).
@@ -424,7 +423,7 @@ fn lookup_cur_matched<'a>(
     interpolations.get(&ident).map(|mut matched| {
         for &(idx, _) in repeats {
             match matched {
-                MatchedTokenTree(_) | MatchedNonterminal(_) => break,
+                MatchedSingle(_) => break,
                 MatchedSeq(ads) => matched = ads.get(idx).unwrap(),
             }
         }
@@ -514,7 +513,7 @@ fn lockstep_iter_size(
             let name = MacroRulesNormalizedIdent::new(*name);
             match lookup_cur_matched(name, interpolations, repeats) {
                 Some(matched) => match matched {
-                    MatchedTokenTree(_) | MatchedNonterminal(_) => LockstepIterSize::Unconstrained,
+                    MatchedSingle(_) => LockstepIterSize::Unconstrained,
                     MatchedSeq(ads) => LockstepIterSize::Constraint(ads.len(), name),
                 },
                 _ => LockstepIterSize::Unconstrained,
@@ -557,7 +556,7 @@ fn count_repetitions<'a>(
     // (or at the top-level of `matched` if no depth is given).
     fn count<'a>(depth_curr: usize, depth_max: usize, matched: &NamedMatch) -> PResult<'a, usize> {
         match matched {
-            MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1),
+            MatchedSingle(_) => Ok(1),
             MatchedSeq(named_matches) => {
                 if depth_curr == depth_max {
                     Ok(named_matches.len())
@@ -571,7 +570,7 @@ fn count_repetitions<'a>(
     /// Maximum depth
     fn depth(counter: usize, matched: &NamedMatch) -> usize {
         match matched {
-            MatchedTokenTree(_) | MatchedNonterminal(_) => counter,
+            MatchedSingle(_) => counter,
             MatchedSeq(named_matches) => {
                 let rslt = counter + 1;
                 if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
@@ -599,7 +598,7 @@ fn count_repetitions<'a>(
         }
     }
 
-    if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
+    if let MatchedSingle(_) = matched {
         return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
     }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 141b8a41801..21aec11b314 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1015,7 +1015,7 @@ impl<'hir> Pat<'hir> {
         use PatKind::*;
         match self.kind {
             Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
-            Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
+            Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
             Slice(before, slice, after) => {
@@ -1042,7 +1042,7 @@ impl<'hir> Pat<'hir> {
         use PatKind::*;
         match self.kind {
             Wild | Never | Lit(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
-            Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
+            Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
             Slice(before, slice, after) => {
@@ -1185,6 +1185,9 @@ pub enum PatKind<'hir> {
     /// A `box` pattern.
     Box(&'hir Pat<'hir>),
 
+    /// A `deref` pattern (currently `deref!()` macro-based syntax).
+    Deref(&'hir Pat<'hir>),
+
     /// A reference pattern (e.g., `&mut (a, b)`).
     Ref(&'hir Pat<'hir>, Mutability),
 
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 3cf1093eeec..468c7fd5c73 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -660,7 +660,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
         PatKind::Tuple(tuple_elements, _) => {
             walk_list!(visitor, visit_pat, tuple_elements);
         }
-        PatKind::Box(ref subpattern) | PatKind::Ref(ref subpattern, _) => {
+        PatKind::Box(ref subpattern)
+        | PatKind::Deref(ref subpattern)
+        | PatKind::Ref(ref subpattern, _) => {
             try_visit!(visitor.visit_pat(subpattern));
         }
         PatKind::Binding(_, _hir_id, ident, ref optional_subpattern) => {
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 3c26729eff8..eb31e1546cf 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -668,7 +668,7 @@ fn resolve_local<'tcx>(
             | PatKind::TupleStruct(_, subpats, _)
             | PatKind::Tuple(subpats, _) => subpats.iter().any(|p| is_binding_pat(p)),
 
-            PatKind::Box(subpat) => is_binding_pat(subpat),
+            PatKind::Box(subpat) | PatKind::Deref(subpat) => is_binding_pat(subpat),
 
             PatKind::Ref(_, _)
             | PatKind::Binding(hir::BindingAnnotation(hir::ByRef::No, _), ..)
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index c7651cf3264..71fdcc76a70 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1808,6 +1808,12 @@ impl<'a> State<'a> {
                     self.pclose();
                 }
             }
+            PatKind::Deref(inner) => {
+                self.word("deref!");
+                self.popen();
+                self.print_pat(inner);
+                self.pclose();
+            }
             PatKind::Ref(inner, mutbl) => {
                 let is_range_inner = matches!(inner.kind, PatKind::Range(..));
                 self.word("&");
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 2dc355b72f6..f3d523efd68 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -463,6 +463,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     }
                     PatKind::Or(_)
                     | PatKind::Box(_)
+                    | PatKind::Deref(_)
                     | PatKind::Ref(..)
                     | PatKind::Wild
                     | PatKind::Err(_) => {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 9307cccf092..d949772f1a3 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -719,7 +719,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 self.cat_pattern_(place_with_id, subpat, op)?;
             }
 
-            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
+            PatKind::Box(subpat) | PatKind::Ref(subpat, _) | PatKind::Deref(subpat) => {
                 // box p1, &p1, &mut p1. we can ignore the mutability of
                 // PatKind::Ref since that information is already contained
                 // in the type.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 633f851c7d5..dad43cb8abe 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -210,10 +210,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Tuple(elements, ddpos) => {
                 self.check_pat_tuple(pat.span, elements, ddpos, expected, pat_info)
             }
-            PatKind::Box(inner) if self.tcx.features().deref_patterns => {
-                self.check_pat_deref(pat.span, inner, expected, pat_info)
-            }
             PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
+            PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
             PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
             PatKind::Slice(before, slice, after) => {
                 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
@@ -297,6 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | PatKind::TupleStruct(..)
             | PatKind::Tuple(..)
             | PatKind::Box(_)
+            | PatKind::Deref(_)
             | PatKind::Range(..)
             | PatKind::Slice(..) => AdjustMode::Peel,
             // A never pattern behaves somewhat like a literal or unit variant.
@@ -762,6 +761,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         | PatKind::Binding(..)
                         | PatKind::Path(..)
                         | PatKind::Box(..)
+                        | PatKind::Deref(_)
                         | PatKind::Ref(..)
                         | PatKind::Lit(..)
                         | PatKind::Range(..)
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 24512dea939..5156a8d3479 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -148,7 +148,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
 
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             dirty_clean_visitor.check_item(id.owner_id.def_id);
         }
 
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 1a82e6c6910..8ba14d37982 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -341,51 +341,22 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone());
 
-            let (codegen_backend, target_override) = match config.make_codegen_backend {
-                None => {
-                    // Build a target without override, so that it can override the backend if needed
-                    let target =
-                        config::build_target_config(&early_dcx, &config.opts, None, &sysroot);
-
-                    let backend = util::get_codegen_backend(
-                        &early_dcx,
-                        &sysroot,
-                        config.opts.unstable_opts.codegen_backend.as_deref(),
-                        &target,
-                    );
-
-                    // target_override is documented to be called before init(), so this is okay
-                    let target_override = backend.target_override(&config.opts);
-
-                    // Assert that we don't use target's override of the backend and
-                    // backend's override of the target at the same time
-                    if config.opts.unstable_opts.codegen_backend.is_none()
-                        && target.default_codegen_backend.is_some()
-                        && target_override.is_some()
-                    {
-                        rustc_middle::bug!(
-                            "Codegen backend requested target override even though the target requested the backend"
-                        );
-                    }
-
-                    (backend, target_override)
-                }
+            let target = config::build_target_config(&early_dcx, &config.opts, &sysroot);
+
+            let codegen_backend = match config.make_codegen_backend {
+                None => util::get_codegen_backend(
+                    &early_dcx,
+                    &sysroot,
+                    config.opts.unstable_opts.codegen_backend.as_deref(),
+                    &target,
+                ),
                 Some(make_codegen_backend) => {
-                    // N.B. `make_codegen_backend` takes precedence over `target.default_codegen_backend`,
-                    //      which is ignored in this case.
-                    let backend = make_codegen_backend(&config.opts);
-
-                    // target_override is documented to be called before init(), so this is okay
-                    let target_override = backend.target_override(&config.opts);
-
-                    (backend, target_override)
+                    // N.B. `make_codegen_backend` takes precedence over
+                    // `target.default_codegen_backend`, which is ignored in this case.
+                    make_codegen_backend(&config.opts)
                 }
             };
 
-            // Re-build target with the (potential) override
-            let target_cfg =
-                config::build_target_config(&early_dcx, &config.opts, target_override, &sysroot);
-
             let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
 
             let bundle = match rustc_errors::fluent_bundle(
@@ -418,7 +389,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 locale_resources,
                 config.lint_caps,
                 config.file_loader,
-                target_cfg,
+                target,
                 sysroot,
                 util::rustc_version_str().unwrap_or("unknown"),
                 config.ice_file,
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 4d8e749d1da..8a27e9a6453 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -41,8 +41,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
 
     let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone());
 
-    let target_cfg =
-        rustc_session::config::build_target_config(&early_dcx, &sessopts, None, &sysroot);
+    let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot);
 
     let sess = build_session(
         early_dcx,
@@ -53,7 +52,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
         vec![],
         Default::default(),
         None,
-        target_cfg,
+        target,
         sysroot,
         "",
         None,
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 91f907e4567..df77181d6f7 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1183,7 +1183,7 @@ impl EarlyLintPass for UnusedParens {
                 self.check_unused_parens_pat(cx, &f.pat, false, false, keep_space);
             },
             // Avoid linting on `i @ (p0 | .. | pn)` and `box (p0 | .. | pn)`, #64106.
-            Ident(.., Some(p)) | Box(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
+            Ident(.., Some(p)) | Box(p) | Deref(p) => self.check_unused_parens_pat(cx, p, true, false, keep_space),
             // Avoid linting on `&(mut x)` as `&mut x` has a different meaning, #55342.
             // Also avoid linting on `& mut? (p0 | .. | pn)`, #64106.
             Ref(p, m) => self.check_unused_parens_pat(cx, p, true, *m == Mutability::Not, keep_space),
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 5e74ce86007..a1bcee84d4c 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -166,12 +166,12 @@ impl<'hir> Map<'hir> {
 
     #[inline]
     pub fn items(self) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_crate_items(()).items.iter().copied()
+        self.tcx.hir_crate_items(()).free_items.iter().copied()
     }
 
     #[inline]
     pub fn module_items(self, module: LocalModDefId) -> impl Iterator<Item = ItemId> + 'hir {
-        self.tcx.hir_module_items(module).items()
+        self.tcx.hir_module_items(module).free_items()
     }
 
     pub fn def_key(self, def_id: LocalDefId) -> DefKey {
@@ -418,7 +418,7 @@ impl<'hir> Map<'hir> {
         V: Visitor<'hir>,
     {
         let krate = self.tcx.hir_crate_items(());
-        walk_list!(visitor, visit_item, krate.items().map(|id| self.item(id)));
+        walk_list!(visitor, visit_item, krate.free_items().map(|id| self.item(id)));
         walk_list!(visitor, visit_trait_item, krate.trait_items().map(|id| self.trait_item(id)));
         walk_list!(visitor, visit_impl_item, krate.impl_items().map(|id| self.impl_item(id)));
         walk_list!(
@@ -436,7 +436,7 @@ impl<'hir> Map<'hir> {
         V: Visitor<'hir>,
     {
         let module = self.tcx.hir_module_items(module);
-        walk_list!(visitor, visit_item, module.items().map(|id| self.item(id)));
+        walk_list!(visitor, visit_item, module.free_items().map(|id| self.item(id)));
         walk_list!(visitor, visit_trait_item, module.trait_items().map(|id| self.trait_item(id)));
         walk_list!(visitor, visit_impl_item, module.impl_items().map(|id| self.impl_item(id)));
         walk_list!(
@@ -1197,7 +1197,7 @@ pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> Mod
     } = collector;
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
-        items: items.into_boxed_slice(),
+        free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
@@ -1226,7 +1226,7 @@ pub(crate) fn hir_crate_items(tcx: TyCtxt<'_>, _: ()) -> ModuleItems {
 
     return ModuleItems {
         submodules: submodules.into_boxed_slice(),
-        items: items.into_boxed_slice(),
+        free_items: items.into_boxed_slice(),
         trait_items: trait_items.into_boxed_slice(),
         impl_items: impl_items.into_boxed_slice(),
         foreign_items: foreign_items.into_boxed_slice(),
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index f9fa8ac2f7a..28f7574f66f 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -22,7 +22,7 @@ use rustc_span::{ErrorGuaranteed, ExpnId};
 #[derive(Debug, HashStable, Encodable, Decodable)]
 pub struct ModuleItems {
     submodules: Box<[OwnerId]>,
-    items: Box<[ItemId]>,
+    free_items: Box<[ItemId]>,
     trait_items: Box<[TraitItemId]>,
     impl_items: Box<[ImplItemId]>,
     foreign_items: Box<[ForeignItemId]>,
@@ -30,14 +30,22 @@ pub struct ModuleItems {
 }
 
 impl ModuleItems {
-    pub fn items(&self) -> impl Iterator<Item = ItemId> + '_ {
-        self.items.iter().copied()
+    /// Returns all non-associated locally defined items in all modules.
+    ///
+    /// Note that this does *not* include associated items of `impl` blocks! It also does not
+    /// include foreign items. If you want to e.g. get all functions, use `definitions()` below.
+    ///
+    /// However, this does include the `impl` blocks themselves.
+    pub fn free_items(&self) -> impl Iterator<Item = ItemId> + '_ {
+        self.free_items.iter().copied()
     }
 
     pub fn trait_items(&self) -> impl Iterator<Item = TraitItemId> + '_ {
         self.trait_items.iter().copied()
     }
 
+    /// Returns all items that are associated with some `impl` block (both inherent and trait impl
+    /// blocks).
     pub fn impl_items(&self) -> impl Iterator<Item = ImplItemId> + '_ {
         self.impl_items.iter().copied()
     }
@@ -47,7 +55,7 @@ impl ModuleItems {
     }
 
     pub fn owners(&self) -> impl Iterator<Item = OwnerId> + '_ {
-        self.items
+        self.free_items
             .iter()
             .map(|id| id.owner_id)
             .chain(self.trait_items.iter().map(|id| id.owner_id))
@@ -63,7 +71,7 @@ impl ModuleItems {
         &self,
         f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
     ) -> Result<(), ErrorGuaranteed> {
-        try_par_for_each_in(&self.items[..], |&id| f(id))
+        try_par_for_each_in(&self.free_items[..], |&id| f(id))
     }
 
     pub fn par_trait_items(
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 0ee97a6bed0..f70ef51107f 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -11,12 +11,18 @@
 /// [`span_bug`]: crate::span_bug
 #[macro_export]
 macro_rules! bug {
-    () => ( $crate::bug!("impossible case reached") );
-    ($msg:expr) => ({ $crate::util::bug::bug_fmt(::std::format_args!($msg)) });
-    ($msg:expr,) => ({ $crate::bug!($msg) });
-    ($fmt:expr, $($arg:tt)+) => ({
+    () => (
+        $crate::bug!("impossible case reached")
+    );
+    ($msg:expr) => (
+        $crate::util::bug::bug_fmt(::std::format_args!($msg))
+    );
+    ($msg:expr,) => (
+        $crate::bug!($msg)
+    );
+    ($fmt:expr, $($arg:tt)+) => (
         $crate::util::bug::bug_fmt(::std::format_args!($fmt, $($arg)+))
-    });
+    );
 }
 
 /// A macro for triggering an ICE with a span.
@@ -30,11 +36,15 @@ macro_rules! bug {
 /// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug
 #[macro_export]
 macro_rules! span_bug {
-    ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
-    ($span:expr, $msg:expr,) => ({ $crate::span_bug!($span, $msg) });
-    ($span:expr, $fmt:expr, $($arg:tt)+) => ({
+    ($span:expr, $msg:expr) => (
+        $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg))
+    );
+    ($span:expr, $msg:expr,) => (
+        $crate::span_bug!($span, $msg)
+    );
+    ($span:expr, $fmt:expr, $($arg:tt)+) => (
         $crate::util::bug::span_bug_fmt($span, ::std::format_args!($fmt, $($arg)+))
-    });
+    );
 }
 
 ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index fc9950a51fb..f684f83a261 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -1179,7 +1179,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
                 write!(f, "{subpattern}")
             }
             PatKind::DerefPattern { ref subpattern } => {
-                write!(f, "k#deref {subpattern}")
+                write!(f, "deref!({subpattern})")
             }
             PatKind::Constant { value } => write!(f, "{value}"),
             PatKind::InlineConstant { def: _, ref subpattern } => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index f4aed91cd72..0a7e9653377 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -257,7 +257,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 return self.lower_path(qpath, pat.hir_id, pat.span);
             }
 
-            hir::PatKind::Box(subpattern) if self.tcx.features().deref_patterns => {
+            hir::PatKind::Deref(subpattern) => {
                 PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern) }
             }
             hir::PatKind::Ref(subpattern, _) | hir::PatKind::Box(subpattern) => {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 0f4b2463c58..1a18a84b358 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1526,7 +1526,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionStrategy) -> Vec<MonoI
 
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             collector.process_item(id);
         }
 
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index a100e2d47bb..e1d26f090e0 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -390,8 +390,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
 parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
 parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
 
-parse_invalid_interpolated_expression = invalid interpolated expression
-
 parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
     .label = invalid suffix `{$suffix}`
     .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 32b56bb7e87..5cad3a568ee 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -851,13 +851,6 @@ pub(crate) struct StructLiteralNotAllowedHereSugg {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_invalid_interpolated_expression)]
-pub(crate) struct InvalidInterpolatedExpression {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(parse_invalid_literal_suffix_on_tuple_index)]
 pub(crate) struct InvalidLiteralSuffixOnTupleIndex {
     #[primary_span]
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index d08c50b5b06..ab5f51eedc3 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -3,11 +3,12 @@ use crate::errors::{
     SuffixedLiteralInAttribute,
 };
 use crate::fluent_generated as fluent;
+use crate::maybe_whole;
 
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 use rustc_ast as ast;
 use rustc_ast::attr;
-use rustc_ast::token::{self, Delimiter, Nonterminal};
+use rustc_ast::token::{self, Delimiter};
 use rustc_errors::{codes::*, Diag, PResult};
 use rustc_span::{sym, BytePos, Span};
 use thin_vec::ThinVec;
@@ -251,25 +252,15 @@ impl<'a> Parser<'a> {
     ///     PATH `=` UNSUFFIXED_LIT
     /// The delimiters or `=` are still put into the resulting token stream.
     pub fn parse_attr_item(&mut self, capture_tokens: bool) -> PResult<'a, ast::AttrItem> {
-        let item = match &self.token.kind {
-            token::Interpolated(nt) => match &nt.0 {
-                Nonterminal::NtMeta(item) => Some(item.clone().into_inner()),
-                _ => None,
-            },
-            _ => None,
+        maybe_whole!(self, NtMeta, |attr| attr.into_inner());
+
+        let do_parse = |this: &mut Self| {
+            let path = this.parse_path(PathStyle::Mod)?;
+            let args = this.parse_attr_args()?;
+            Ok(ast::AttrItem { path, args, tokens: None })
         };
-        Ok(if let Some(item) = item {
-            self.bump();
-            item
-        } else {
-            let do_parse = |this: &mut Self| {
-                let path = this.parse_path(PathStyle::Mod)?;
-                let args = this.parse_attr_args()?;
-                Ok(ast::AttrItem { path, args, tokens: None })
-            };
-            // Attr items don't have attributes
-            if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }?
-        })
+        // Attr items don't have attributes
+        if capture_tokens { self.collect_tokens_no_attrs(do_parse) } else { do_parse(self) }
     }
 
     /// Parses attributes that appear after the opening of an item. These should
@@ -371,22 +362,18 @@ impl<'a> Parser<'a> {
     /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
     /// ```
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
-        let nt_meta = match &self.token.kind {
-            token::Interpolated(nt) => match &nt.0 {
-                token::NtMeta(e) => Some(e.clone()),
-                _ => None,
-            },
-            _ => None,
-        };
-
-        if let Some(item) = nt_meta {
-            match item.meta(item.path.span) {
+        // We can't use `maybe_whole` here because it would bump in the `None`
+        // case, which we don't want.
+        if let token::Interpolated(nt) = &self.token.kind
+            && let token::NtMeta(attr_item) = &nt.0
+        {
+            match attr_item.meta(attr_item.path.span) {
                 Some(meta) => {
                     self.bump();
                     return Ok(meta);
                 }
                 None => self.unexpected()?,
-            };
+            }
         }
 
         let lo = self.token.span;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 6256db99251..d175d1c04c8 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -2053,16 +2053,6 @@ impl<'a> Parser<'a> {
         &mut self,
         mk_lit_char: impl FnOnce(Symbol, Span) -> L,
     ) -> PResult<'a, L> {
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtExpr(e) | token::NtLiteral(e) = &nt.0
-            && matches!(e.kind, ExprKind::Err(_))
-        {
-            let mut err = self
-                .dcx()
-                .create_err(errors::InvalidInterpolatedExpression { span: self.token.span });
-            err.downgrade_to_delayed_bug();
-            return Err(err);
-        }
         let token = self.token.clone();
         let err = |self_: &Self| {
             let msg = format!("unexpected token: {}", super::token_descr(&token));
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 18d210eacfa..d54eb8dc4c9 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -6,6 +6,7 @@ use super::{
 };
 use crate::errors::{self, MacroExpandsToAdtField};
 use crate::fluent_generated as fluent;
+use crate::maybe_whole;
 use ast::token::IdentIsRaw;
 use rustc_ast::ast::*;
 use rustc_ast::ptr::P;
@@ -115,17 +116,10 @@ impl<'a> Parser<'a> {
         fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
-        // Don't use `maybe_whole` so that we have precise control
-        // over when we bump the parser
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtItem(item) = &nt.0
-        {
-            let mut item = item.clone();
-            self.bump();
-
+        maybe_whole!(self, NtItem, |item| {
             attrs.prepend_to_nt_inner(&mut item.attrs);
-            return Ok(Some(item.into_inner()));
-        };
+            Some(item.into_inner())
+        });
 
         let item =
             self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7315e096464..de83528b52c 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -20,7 +20,7 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma};
 pub use path::PathStyle;
 
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
@@ -93,12 +93,13 @@ pub enum TrailingToken {
 #[macro_export]
 macro_rules! maybe_whole {
     ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
-        if let token::Interpolated(nt) = &$p.token.kind {
-            if let token::$constructor(x) = &nt.0 {
-                let $x = x.clone();
-                $p.bump();
-                return Ok($e);
-            }
+        if let token::Interpolated(nt) = &$p.token.kind
+            && let token::$constructor(x) = &nt.0
+        {
+            #[allow(unused_mut)]
+            let mut $x = x.clone();
+            $p.bump();
+            return Ok($e);
         }
     };
 }
@@ -1407,7 +1408,7 @@ impl<'a> Parser<'a> {
     /// so emit a proper diagnostic.
     // Public for rustfmt usage.
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
-        maybe_whole!(self, NtVis, |x| x.into_inner());
+        maybe_whole!(self, NtVis, |vis| vis.into_inner());
 
         if !self.eat_keyword(kw::Pub) {
             // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
@@ -1584,8 +1585,21 @@ pub enum FlatToken {
     Empty,
 }
 
-#[derive(Debug)]
-pub enum ParseNtResult {
-    Nt(Nonterminal),
+// Metavar captures of various kinds.
+#[derive(Clone, Debug)]
+pub enum ParseNtResult<NtType> {
     Tt(TokenTree),
+    Nt(NtType),
+}
+
+impl<T> ParseNtResult<T> {
+    pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
+    where
+        F: FnMut(T) -> U,
+    {
+        match self {
+            ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
+            ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
+        }
+    }
 }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index f1572a18a8b..36a00df7b44 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,5 +1,5 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
+use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
@@ -66,15 +66,14 @@ impl<'a> Parser<'a> {
                 token::Interpolated(nt) => may_be_ident(&nt.0),
                 _ => false,
             },
-            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
-                match &token.kind {
+            NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
                 token::Ident(..) |                          // box, ref, mut, and other identifiers (can stricten)
                 token::OpenDelim(Delimiter::Parenthesis) |  // tuple pattern
                 token::OpenDelim(Delimiter::Bracket) |      // slice pattern
                 token::BinOp(token::And) |                  // reference
                 token::BinOp(token::Minus) |                // negative literal
                 token::AndAnd |                             // double reference
-                token::Literal(_) |                        // literal
+                token::Literal(_) |                         // literal
                 token::DotDot |                             // range pattern (future compat)
                 token::DotDotDot |                          // range pattern (future compat)
                 token::ModSep |                             // path
@@ -84,8 +83,7 @@ impl<'a> Parser<'a> {
                 token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
                 token::Interpolated(nt) => may_be_ident(&nt.0),
                 _ => false,
-            }
-            }
+            },
             NonterminalKind::Lifetime => match &token.kind {
                 token::Lifetime(_) => true,
                 token::Interpolated(nt) => {
@@ -102,7 +100,10 @@ impl<'a> Parser<'a> {
     /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
     /// site.
     #[inline]
-    pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
+    pub fn parse_nonterminal(
+        &mut self,
+        kind: NonterminalKind,
+    ) -> PResult<'a, ParseNtResult<Nonterminal>> {
         // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
         // which requires having captured tokens available. Since we cannot determine
         // in advance whether or not a proc-macro will be (transitively) invoked,
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 88ae1b5420f..fbc28859535 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -435,7 +435,7 @@ impl<'a> Parser<'a> {
         syntax_loc: Option<PatternLocation>,
     ) -> PResult<'a, P<Pat>> {
         maybe_recover_from_interpolated_ty_qpath!(self, true);
-        maybe_whole!(self, NtPat, |x| x);
+        maybe_whole!(self, NtPat, |pat| pat);
 
         let mut lo = self.token.span;
 
@@ -498,11 +498,14 @@ impl<'a> Parser<'a> {
             } else {
                 PatKind::Lit(const_expr)
             }
+        } else if self.is_builtin() {
+            self.parse_pat_builtin()?
+        }
         // Don't eagerly error on semantically invalid tokens when matching
         // declarative macros, as the input to those doesn't have to be
         // semantically valid. For attribute/derive proc macros this is not the
         // case, so doing the recovery for them is fine.
-        } else if self.can_be_ident_pat()
+        else if self.can_be_ident_pat()
             || (self.is_lit_bad_ident().is_some() && self.may_recover())
         {
             // Parse `ident @ pat`
@@ -1119,6 +1122,21 @@ impl<'a> Parser<'a> {
         .contains(&self.token.kind)
     }
 
+    fn parse_pat_builtin(&mut self) -> PResult<'a, PatKind> {
+        self.parse_builtin(|self_, _lo, ident| {
+            Ok(match ident.name {
+                // builtin#deref(PAT)
+                sym::deref => Some(ast::PatKind::Deref(self_.parse_pat_allow_top_alt(
+                    None,
+                    RecoverComma::Yes,
+                    RecoverColon::Yes,
+                    CommaRecoveryMode::LikelyTuple,
+                )?)),
+                _ => None,
+            })
+        })
+    }
+
     /// Parses `box pat`
     fn parse_pat_box(&mut self) -> PResult<'a, PatKind> {
         let box_span = self.prev_token.span;
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fc907760531..6601011665b 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -40,8 +40,8 @@ impl<'a> Parser<'a> {
         }))
     }
 
-    /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
-    /// or not we have attributes
+    /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of
+    /// whether or not we have attributes.
     // Public for `cfg_eval` macro expansion.
     pub fn parse_stmt_without_recovery(
         &mut self,
@@ -51,18 +51,12 @@ impl<'a> Parser<'a> {
         let attrs = self.parse_outer_attributes()?;
         let lo = self.token.span;
 
-        // Don't use `maybe_whole` so that we have precise control
-        // over when we bump the parser
-        if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtStmt(stmt) = &nt.0
-        {
-            let mut stmt = stmt.clone();
-            self.bump();
+        maybe_whole!(self, NtStmt, |stmt| {
             stmt.visit_attrs(|stmt_attrs| {
                 attrs.prepend_to_nt_inner(stmt_attrs);
             });
-            return Ok(Some(stmt.into_inner()));
-        }
+            Some(stmt.into_inner())
+        });
 
         if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
             self.bump();
@@ -539,7 +533,7 @@ impl<'a> Parser<'a> {
         blk_mode: BlockCheckMode,
         can_be_struct_literal: bool,
     ) -> PResult<'a, (AttrVec, P<Block>)> {
-        maybe_whole!(self, NtBlock, |x| (AttrVec::new(), x));
+        maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
 
         let maybe_ident = self.prev_token.clone();
         self.maybe_recover_unexpected_block_label();
@@ -643,7 +637,7 @@ impl<'a> Parser<'a> {
         recover: AttemptLocalParseRecovery,
     ) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
-        maybe_whole!(self, NtStmt, |x| Some(x.into_inner()));
+        maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner()));
 
         let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else {
             return Ok(None);
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 2385c18c089..1cea32cb90f 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -250,7 +250,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
-        maybe_whole!(self, NtTy, |x| x);
+        maybe_whole!(self, NtTy, |ty| ty);
 
         let lo = self.token.span;
         let mut impl_dyn_multi = false;
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 350f7e166bf..c3124556648 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -831,7 +831,7 @@ fn create_and_seed_worklist(
         .collect::<Vec<_>>();
 
     let crate_items = tcx.hir_crate_items(());
-    for id in crate_items.items() {
+    for id in crate_items.free_items() {
         check_item(tcx, &mut worklist, &mut struct_constructors, &mut unsolved_impl_item, id);
     }
 
@@ -1084,7 +1084,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
 
     let module_items = tcx.hir_module_items(module);
 
-    for item in module_items.items() {
+    for item in module_items.free_items() {
         let def_kind = tcx.def_kind(item.owner_id);
 
         let mut dead_codes = Vec::new();
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d742ffc69e4..d0dba938b3b 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -300,6 +300,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
                 Path,
                 Tuple,
                 Box,
+                Deref,
                 Ref,
                 Lit,
                 Range,
@@ -566,6 +567,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
                 Path,
                 Tuple,
                 Box,
+                Deref,
                 Ref,
                 Lit,
                 Range,
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index b7135de08ba..c2e604b02b3 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -437,7 +437,7 @@ fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet {
         // trait is a lang item.
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities);
         }
 
diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml
index b9bdcb41929..6357d18b9da 100644
--- a/compiler/rustc_pattern_analysis/Cargo.toml
+++ b/compiler/rustc_pattern_analysis/Cargo.toml
@@ -22,6 +22,10 @@ smallvec = { version = "1.8.1", features = ["union"] }
 tracing = "0.1"
 # tidy-alphabetical-end
 
+[dev-dependencies]
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "ansi"] }
+tracing-tree = "0.2.0"
+
 [features]
 default = ["rustc"]
 rustc = [
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index 5b58d7f43b2..95c5556410d 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -819,6 +819,81 @@ impl<Cx: PatCx> Constructor<Cx> {
             }
         })
     }
+
+    pub(crate) fn fmt_fields(
+        &self,
+        f: &mut fmt::Formatter<'_>,
+        ty: &Cx::Ty,
+        mut fields: impl Iterator<Item = impl fmt::Debug>,
+    ) -> fmt::Result {
+        let mut first = true;
+        let mut start_or_continue = |s| {
+            if first {
+                first = false;
+                ""
+            } else {
+                s
+            }
+        };
+        let mut start_or_comma = || start_or_continue(", ");
+
+        match self {
+            Struct | Variant(_) | UnionField => {
+                Cx::write_variant_name(f, self, ty)?;
+                // Without `cx`, we can't know which field corresponds to which, so we can't
+                // get the names of the fields. Instead we just display everything as a tuple
+                // struct, which should be good enough.
+                write!(f, "(")?;
+                for p in fields {
+                    write!(f, "{}{:?}", start_or_comma(), p)?;
+                }
+                write!(f, ")")?;
+            }
+            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
+            // be careful to detect strings here. However a string literal pattern will never
+            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
+            Ref => {
+                write!(f, "&{:?}", &fields.next().unwrap())?;
+            }
+            Slice(slice) => {
+                write!(f, "[")?;
+                match slice.kind {
+                    SliceKind::FixedLen(_) => {
+                        for p in fields {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                    SliceKind::VarLen(prefix_len, _) => {
+                        for p in fields.by_ref().take(prefix_len) {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                        write!(f, "{}..", start_or_comma())?;
+                        for p in fields {
+                            write!(f, "{}{:?}", start_or_comma(), p)?;
+                        }
+                    }
+                }
+                write!(f, "]")?;
+            }
+            Bool(b) => write!(f, "{b}")?,
+            // Best-effort, will render signed ranges incorrectly
+            IntRange(range) => write!(f, "{range:?}")?,
+            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
+            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?,
+            Str(value) => write!(f, "{value:?}")?,
+            Opaque(..) => write!(f, "<constant pattern>")?,
+            Or => {
+                for pat in fields {
+                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
+                }
+            }
+            Never => write!(f, "!")?,
+            Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
+                write!(f, "_ : {:?}", ty)?
+            }
+        }
+        Ok(())
+    }
 }
 
 #[derive(Debug, Clone, Copy)]
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 5c57c990323..1a1da5c55f6 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -49,6 +49,12 @@ pub mod index {
         }
     }
 
+    impl<V> FromIterator<V> for IdxContainer<usize, V> {
+        fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
+            Self(iter.into_iter().enumerate().collect())
+        }
+    }
+
     #[derive(Debug)]
     pub struct IdxSet<T>(pub rustc_hash::FxHashSet<T>);
     impl<T: Idx> IdxSet<T> {
@@ -120,7 +126,8 @@ pub trait PatCx: Sized + fmt::Debug {
     /// `DeconstructedPat`. Only invoqued when `pat.ctor()` is `Struct | Variant(_) | UnionField`.
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<Self>,
+        ctor: &crate::constructor::Constructor<Self>,
+        ty: &Self::Ty,
     ) -> fmt::Result;
 
     /// Raise a bug.
diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs
index e7eed673c94..5f388ee9f89 100644
--- a/compiler/rustc_pattern_analysis/src/pat.rs
+++ b/compiler/rustc_pattern_analysis/src/pat.rs
@@ -138,81 +138,11 @@ impl<Cx: PatCx> DeconstructedPat<Cx> {
 /// This is best effort and not good enough for a `Display` impl.
 impl<Cx: PatCx> fmt::Debug for DeconstructedPat<Cx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let pat = self;
-        let mut first = true;
-        let mut start_or_continue = |s| {
-            if first {
-                first = false;
-                ""
-            } else {
-                s
-            }
-        };
-        let mut start_or_comma = || start_or_continue(", ");
-
         let mut fields: Vec<_> = (0..self.arity).map(|_| PatOrWild::Wild).collect();
         for ipat in self.iter_fields() {
             fields[ipat.idx] = PatOrWild::Pat(&ipat.pat);
         }
-
-        match pat.ctor() {
-            Struct | Variant(_) | UnionField => {
-                Cx::write_variant_name(f, pat)?;
-                // Without `cx`, we can't know which field corresponds to which, so we can't
-                // get the names of the fields. Instead we just display everything as a tuple
-                // struct, which should be good enough.
-                write!(f, "(")?;
-                for p in fields {
-                    write!(f, "{}", start_or_comma())?;
-                    write!(f, "{p:?}")?;
-                }
-                write!(f, ")")
-            }
-            // Note: given the expansion of `&str` patterns done in `expand_pattern`, we should
-            // be careful to detect strings here. However a string literal pattern will never
-            // be reported as a non-exhaustiveness witness, so we can ignore this issue.
-            Ref => {
-                write!(f, "&{:?}", &fields[0])
-            }
-            Slice(slice) => {
-                write!(f, "[")?;
-                match slice.kind {
-                    SliceKind::FixedLen(_) => {
-                        for p in fields {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                    SliceKind::VarLen(prefix_len, _) => {
-                        for p in &fields[..prefix_len] {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                        write!(f, "{}", start_or_comma())?;
-                        write!(f, "..")?;
-                        for p in &fields[prefix_len..] {
-                            write!(f, "{}{:?}", start_or_comma(), p)?;
-                        }
-                    }
-                }
-                write!(f, "]")
-            }
-            Bool(b) => write!(f, "{b}"),
-            // Best-effort, will render signed ranges incorrectly
-            IntRange(range) => write!(f, "{range:?}"),
-            F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"),
-            Str(value) => write!(f, "{value:?}"),
-            Opaque(..) => write!(f, "<constant pattern>"),
-            Or => {
-                for pat in fields {
-                    write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
-                }
-                Ok(())
-            }
-            Never => write!(f, "!"),
-            Wildcard | Missing | NonExhaustive | Hidden | PrivateUninhabited => {
-                write!(f, "_ : {:?}", pat.ty())
-            }
-        }
+        self.ctor().fmt_fields(f, self.ty(), fields.into_iter())
     }
 }
 
@@ -295,7 +225,6 @@ impl<'p, Cx: PatCx> fmt::Debug for PatOrWild<'p, Cx> {
 
 /// Same idea as `DeconstructedPat`, except this is a fictitious pattern built up for diagnostics
 /// purposes. As such they don't use interning and can be cloned.
-#[derive(Debug)]
 pub struct WitnessPat<Cx: PatCx> {
     ctor: Constructor<Cx>,
     pub(crate) fields: Vec<WitnessPat<Cx>>,
@@ -353,3 +282,10 @@ impl<Cx: PatCx> WitnessPat<Cx> {
         self.fields.iter()
     }
 }
+
+/// This is best effort and not good enough for a `Display` impl.
+impl<Cx: PatCx> fmt::Debug for WitnessPat<Cx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.ctor().fmt_fields(f, self.ty(), self.fields.iter())
+    }
+}
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index 4cb306b1950..ae3eabe1745 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -880,13 +880,14 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> {
 
     fn write_variant_name(
         f: &mut fmt::Formatter<'_>,
-        pat: &crate::pat::DeconstructedPat<Self>,
+        ctor: &crate::constructor::Constructor<Self>,
+        ty: &Self::Ty,
     ) -> fmt::Result {
-        if let ty::Adt(adt, _) = pat.ty().kind() {
+        if let ty::Adt(adt, _) = ty.kind() {
             if adt.is_box() {
                 write!(f, "Box")?
             } else {
-                let variant = adt.variant(Self::variant_index_for_adt(pat.ctor(), *adt));
+                let variant = adt.variant(Self::variant_index_for_adt(ctor, *adt));
                 write!(f, "{}", variant.name)?;
             }
         }
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 3760db8b688..cdc03eaeb37 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -1042,7 +1042,7 @@ struct MatrixRow<'p, Cx: PatCx> {
     is_under_guard: bool,
     /// When we specialize, we remember which row of the original matrix produced a given row of the
     /// specialized matrix. When we unspecialize, we use this to propagate usefulness back up the
-    /// callstack.
+    /// callstack. On creation, this stores the index of the original match arm.
     parent_row: usize,
     /// False when the matrix is just built. This is set to `true` by
     /// [`compute_exhaustiveness_and_usefulness`] if the arm is found to be useful.
@@ -1163,10 +1163,10 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> {
             place_info: smallvec![place_info],
             wildcard_row_is_relevant: true,
         };
-        for (row_id, arm) in arms.iter().enumerate() {
+        for (arm_id, arm) in arms.iter().enumerate() {
             let v = MatrixRow {
                 pats: PatStack::from_pattern(arm.pat),
-                parent_row: row_id, // dummy, we don't read it
+                parent_row: arm_id,
                 is_under_guard: arm.has_guard,
                 useful: false,
                 intersects: BitSet::new_empty(0), // Initialized in `Matrix::expand_and_push`.
@@ -1738,6 +1738,9 @@ pub struct UsefulnessReport<'p, Cx: PatCx> {
     /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of
     /// exhaustiveness.
     pub non_exhaustiveness_witnesses: Vec<WitnessPat<Cx>>,
+    /// For each arm, a set of indices of arms above it that have non-empty intersection, i.e. there
+    /// is a value matched by both arms. This may miss real intersections.
+    pub arm_intersections: Vec<BitSet<usize>>,
 }
 
 /// Computes whether a match is exhaustive and which of its arms are useful.
@@ -1769,5 +1772,19 @@ pub fn compute_match_usefulness<'p, Cx: PatCx>(
         })
         .collect();
 
-    Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
+    let mut arm_intersections: Vec<_> =
+        arms.iter().enumerate().map(|(i, _)| BitSet::new_empty(i)).collect();
+    for row in matrix.rows() {
+        let arm_id = row.parent_row;
+        for intersection in row.intersects.iter() {
+            // Convert the matrix row ids into arm ids (they can differ because we expand or-patterns).
+            let arm_intersection = matrix.rows[intersection].parent_row;
+            // Note: self-intersection can happen with or-patterns.
+            if arm_intersection != arm_id {
+                arm_intersections[arm_id].insert(arm_intersection);
+            }
+        }
+    }
+
+    Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses, arm_intersections })
 }
diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs
new file mode 100644
index 00000000000..e72fddb9e9a
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs
@@ -0,0 +1,315 @@
+use rustc_pattern_analysis::{
+    constructor::{
+        Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility,
+    },
+    usefulness::{PlaceValidity, UsefulnessReport},
+    Captures, MatchArm, PatCx, PrivateUninhabitedField,
+};
+
+/// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup.
+pub fn init_tracing() {
+    use tracing_subscriber::layer::SubscriberExt;
+    use tracing_subscriber::util::SubscriberInitExt;
+    use tracing_subscriber::Layer;
+    let _ = tracing_tree::HierarchicalLayer::default()
+        .with_writer(std::io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(true)
+        .with_targets(true)
+        .with_indent_amount(2)
+        .with_subscriber(
+            tracing_subscriber::Registry::default()
+                .with(tracing_subscriber::EnvFilter::from_default_env()),
+        )
+        .try_init();
+}
+
+/// A simple set of types.
+#[allow(dead_code)]
+#[derive(Debug, Copy, Clone)]
+pub enum Ty {
+    /// Booleans
+    Bool,
+    /// 8-bit unsigned integers
+    U8,
+    /// Tuples.
+    Tuple(&'static [Ty]),
+    /// A struct with `arity` fields of type `ty`.
+    BigStruct { arity: usize, ty: &'static Ty },
+    /// A enum with `arity` variants of type `ty`.
+    BigEnum { arity: usize, ty: &'static Ty },
+}
+
+/// The important logic.
+impl Ty {
+    pub fn sub_tys(&self, ctor: &Constructor<Cx>) -> Vec<Self> {
+        use Constructor::*;
+        match (ctor, *self) {
+            (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(),
+            (Struct, Ty::BigStruct { arity, ty }) => (0..arity).map(|_| *ty).collect(),
+            (Variant(_), Ty::BigEnum { ty, .. }) => vec![*ty],
+            (Bool(..) | IntRange(..) | NonExhaustive | Missing | Wildcard, _) => vec![],
+            _ => panic!("Unexpected ctor {ctor:?} for type {self:?}"),
+        }
+    }
+
+    pub fn ctor_set(&self) -> ConstructorSet<Cx> {
+        match *self {
+            Ty::Bool => ConstructorSet::Bool,
+            Ty::U8 => ConstructorSet::Integers {
+                range_1: IntRange::from_range(
+                    MaybeInfiniteInt::new_finite_uint(0),
+                    MaybeInfiniteInt::new_finite_uint(255),
+                    RangeEnd::Included,
+                ),
+                range_2: None,
+            },
+            Ty::Tuple(..) | Ty::BigStruct { .. } => ConstructorSet::Struct { empty: false },
+            Ty::BigEnum { arity, .. } => ConstructorSet::Variants {
+                variants: (0..arity).map(|_| VariantVisibility::Visible).collect(),
+                non_exhaustive: false,
+            },
+        }
+    }
+
+    pub fn write_variant_name(
+        &self,
+        f: &mut std::fmt::Formatter<'_>,
+        ctor: &Constructor<Cx>,
+    ) -> std::fmt::Result {
+        match (*self, ctor) {
+            (Ty::Tuple(..), _) => Ok(()),
+            (Ty::BigStruct { .. }, _) => write!(f, "BigStruct"),
+            (Ty::BigEnum { .. }, Constructor::Variant(i)) => write!(f, "BigEnum::Variant{i}"),
+            _ => write!(f, "{:?}::{:?}", self, ctor),
+        }
+    }
+}
+
+/// Compute usefulness in our simple context (and set up tracing for easier debugging).
+pub fn compute_match_usefulness<'p>(
+    arms: &[MatchArm<'p, Cx>],
+    ty: Ty,
+    scrut_validity: PlaceValidity,
+    complexity_limit: Option<usize>,
+) -> Result<UsefulnessReport<'p, Cx>, ()> {
+    init_tracing();
+    rustc_pattern_analysis::usefulness::compute_match_usefulness(
+        &Cx,
+        arms,
+        ty,
+        scrut_validity,
+        complexity_limit,
+    )
+}
+
+#[derive(Debug)]
+pub struct Cx;
+
+/// The context for pattern analysis. Forwards anything interesting to `Ty` methods.
+impl PatCx for Cx {
+    type Ty = Ty;
+    type Error = ();
+    type VariantIdx = usize;
+    type StrLit = ();
+    type ArmData = ();
+    type PatData = ();
+
+    fn is_exhaustive_patterns_feature_on(&self) -> bool {
+        false
+    }
+
+    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
+        false
+    }
+
+    fn ctor_arity(&self, ctor: &Constructor<Self>, ty: &Self::Ty) -> usize {
+        ty.sub_tys(ctor).len()
+    }
+
+    fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a Constructor<Self>,
+        ty: &'a Self::Ty,
+    ) -> impl Iterator<Item = (Self::Ty, PrivateUninhabitedField)> + ExactSizeIterator + Captures<'a>
+    {
+        ty.sub_tys(ctor).into_iter().map(|ty| (ty, PrivateUninhabitedField(false)))
+    }
+
+    fn ctors_for_ty(&self, ty: &Self::Ty) -> Result<ConstructorSet<Self>, Self::Error> {
+        Ok(ty.ctor_set())
+    }
+
+    fn write_variant_name(
+        f: &mut std::fmt::Formatter<'_>,
+        ctor: &Constructor<Self>,
+        ty: &Self::Ty,
+    ) -> std::fmt::Result {
+        ty.write_variant_name(f, ctor)
+    }
+
+    fn bug(&self, fmt: std::fmt::Arguments<'_>) -> Self::Error {
+        panic!("{}", fmt)
+    }
+
+    /// Abort when reaching the complexity limit. This is what we'll check in tests.
+    fn complexity_exceeded(&self) -> Result<(), Self::Error> {
+        Err(())
+    }
+}
+
+/// Construct a single pattern; see `pats!()`.
+#[allow(unused_macros)]
+macro_rules! pat {
+    ($($rest:tt)*) => {{
+        let mut vec = pats!($($rest)*);
+        vec.pop().unwrap()
+    }};
+}
+
+/// A macro to construct patterns. Called like `pats!(type_expr; pattern, pattern, ..)` and returns
+/// a `Vec<DeconstructedPat>`. A pattern can be nested and looks like `Constructor(pat, pat)` or
+/// `Constructor { .i: pat, .j: pat }`, where `Constructor` is `Struct`, `Variant.i` (with index
+/// `i`), as well as booleans and integer ranges.
+///
+/// The general structure of the macro is a tt-muncher with several stages identified with
+/// `@something(args)`. The args are a key-value list (the keys ensure we don't mix the arguments
+/// around) which is passed down and modified as needed. We then parse token-trees from
+/// left-to-right. Non-trivial recursion happens when we parse the arguments to a pattern: we
+/// recurse to parse the tokens inside `{..}`/`(..)`, and then we continue parsing anything that
+/// follows.
+macro_rules! pats {
+    // Entrypoint
+    // Parse `type; ..`
+    ($ty:expr; $($rest:tt)*) => {{
+        #[allow(unused_imports)]
+        use rustc_pattern_analysis::{
+            constructor::{Constructor, IntRange, MaybeInfiniteInt, RangeEnd},
+            pat::DeconstructedPat,
+        };
+        let ty = $ty;
+        // The heart of the macro is designed to push `IndexedPat`s into a `Vec`, so we work around
+        // that.
+        let sub_tys = ::std::iter::repeat(&ty);
+        let mut vec = Vec::new();
+        pats!(@ctor(vec:vec, sub_tys:sub_tys, idx:0) $($rest)*);
+        vec.into_iter().map(|ipat| ipat.pat).collect::<Vec<_>>()
+    }};
+
+    // Parse `constructor ..`
+
+    (@ctor($($args:tt)*) true $($rest:tt)*) => {{
+        let ctor = Constructor::Bool(true);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) false $($rest:tt)*) => {{
+        let ctor = Constructor::Bool(false);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Struct $($rest:tt)*) => {{
+        let ctor = Constructor::Struct;
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) ( $($fields:tt)* ) $($rest:tt)*) => {{
+        let ctor = Constructor::Struct; // tuples
+        pats!(@pat($($args)*, ctor:ctor) ( $($fields)* ) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Variant.$variant:ident $($rest:tt)*) => {{
+        let ctor = Constructor::Variant($variant);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) Variant.$variant:literal $($rest:tt)*) => {{
+        let ctor = Constructor::Variant($variant);
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) _ $($rest:tt)*) => {{
+        let ctor = Constructor::Wildcard;
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+
+    // Integers and int ranges
+    (@ctor($($args:tt)*) $($start:literal)?..$end:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+ $end),
+            RangeEnd::Excluded,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $($start:literal)?.. $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+),
+            RangeEnd::Excluded,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $($start:literal)?..=$end:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $($start)?),
+            pats!(@rangeboundary+ $end),
+            RangeEnd::Included,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    (@ctor($($args:tt)*) $int:literal $($rest:tt)*) => {{
+        let ctor = Constructor::IntRange(IntRange::from_range(
+            pats!(@rangeboundary- $int),
+            pats!(@rangeboundary+ $int),
+            RangeEnd::Included,
+        ));
+        pats!(@pat($($args)*, ctor:ctor) $($rest)*)
+    }};
+    // Utility to manage range boundaries.
+    (@rangeboundary $sign:tt $int:literal) => { MaybeInfiniteInt::new_finite_uint($int) };
+    (@rangeboundary -) => { MaybeInfiniteInt::NegInfinity };
+    (@rangeboundary +) => { MaybeInfiniteInt::PosInfinity };
+
+    // Parse subfields: `(..)` or `{..}`
+
+    // Constructor with no fields, e.g. `bool` or `Variant.1`.
+    (@pat($($args:tt)*) $(,)?) => {
+        pats!(@pat($($args)*) {})
+    };
+    (@pat($($args:tt)*) , $($rest:tt)*) => {
+        pats!(@pat($($args)*) {}, $($rest)*)
+    };
+    // `(..)` and `{..}` are treated the same.
+    (@pat($($args:tt)*) ( $($subpat:tt)* ) $($rest:tt)*) => {{
+        pats!(@pat($($args)*) { $($subpat)* } $($rest)*)
+    }};
+    (@pat(vec:$vec:expr, sub_tys:$sub_tys:expr, idx:$idx:expr, ctor:$ctor:expr) { $($fields:tt)* } $($rest:tt)*) => {{
+        let sub_tys = $sub_tys;
+        let index = $idx;
+        // Silly dance to work with both a vec and `iter::repeat()`.
+        let ty = *(&sub_tys).clone().into_iter().nth(index).unwrap();
+        let ctor = $ctor;
+        let ctor_sub_tys = &ty.sub_tys(&ctor);
+        #[allow(unused_mut)]
+        let mut fields = Vec::new();
+        // Parse subpatterns (note the leading comma).
+        pats!(@fields(idx:0, vec:fields, sub_tys:ctor_sub_tys) ,$($fields)*);
+        let arity = ctor_sub_tys.len();
+        let pat = DeconstructedPat::new(ctor, fields, arity, ty, ()).at_index(index);
+        $vec.push(pat);
+
+        // Continue parsing further patterns.
+        pats!(@fields(idx:index+1, vec:$vec, sub_tys:sub_tys) $($rest)*);
+    }};
+
+    // Parse fields one by one.
+
+    // No fields left.
+    (@fields($($args:tt)*) $(,)?) => {};
+    // `.i: pat` sets the current index to `i`.
+    (@fields(idx:$_idx:expr, $($args:tt)*) , .$idx:literal : $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+    (@fields(idx:$_idx:expr, $($args:tt)*) , .$idx:ident : $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+    // Field without an explicit index; we use the current index which gets incremented above.
+    (@fields(idx:$idx:expr, $($args:tt)*) , $($rest:tt)*) => {{
+        pats!(@ctor($($args)*, idx:$idx) $($rest)*);
+    }};
+}
diff --git a/compiler/rustc_pattern_analysis/tests/complexity.rs b/compiler/rustc_pattern_analysis/tests/complexity.rs
new file mode 100644
index 00000000000..93f455c6257
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/complexity.rs
@@ -0,0 +1,109 @@
+//! Test the pattern complexity limit.
+use common::*;
+use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns. Ignore the report; we only care whether we exceeded the
+/// limit or not.
+fn check(patterns: &[DeconstructedPat<Cx>], complexity_limit: usize) -> Result<(), ()> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, Some(complexity_limit))
+        .map(|_report| ())
+}
+
+/// Asserts that analyzing this match takes exactly `complexity` steps.
+#[track_caller]
+fn assert_complexity(patterns: Vec<DeconstructedPat<Cx>>, complexity: usize) {
+    assert!(check(&patterns, complexity).is_ok());
+    assert!(check(&patterns, complexity - 1).is_err());
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigStruct { field01: true, .. } => {}
+///     BigStruct { field02: true, .. } => {}
+///     BigStruct { field03: true, .. } => {}
+///     BigStruct { field04: true, .. } => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn diagonal_match(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let struct_ty = Ty::BigStruct { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: true }));
+    }
+    patterns.push(pat!(struct_ty; _));
+    patterns
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigStruct { field01: true, .. } => {}
+///     BigStruct { field02: true, .. } => {}
+///     BigStruct { field03: true, .. } => {}
+///     BigStruct { field04: true, .. } => {}
+///     ...
+///     BigStruct { field01: false, .. } => {}
+///     BigStruct { field02: false, .. } => {}
+///     BigStruct { field03: false, .. } => {}
+///     BigStruct { field04: false, .. } => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn diagonal_exponential_match(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let struct_ty = Ty::BigStruct { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: true }));
+    }
+    for i in 0..arity {
+        patterns.push(pat!(struct_ty; Struct { .i: false }));
+    }
+    patterns.push(pat!(struct_ty; _));
+    patterns
+}
+
+#[test]
+fn test_diagonal_struct_match() {
+    // These cases are nicely linear: we check `arity` patterns with exactly one `true`, matching
+    // in 2 branches each, and a final pattern with all `false`, matching only the `_` branch.
+    assert_complexity(diagonal_match(20), 41);
+    assert_complexity(diagonal_match(30), 61);
+    // This case goes exponential.
+    assert!(check(&diagonal_exponential_match(10), 10000).is_err());
+}
+
+/// Construct a match like:
+/// ```ignore(illustrative)
+/// match ... {
+///     BigEnum::Variant1(_) => {}
+///     BigEnum::Variant2(_) => {}
+///     BigEnum::Variant3(_) => {}
+///     ...
+///     _ => {}
+/// }
+/// ```
+fn big_enum(arity: usize) -> Vec<DeconstructedPat<Cx>> {
+    let enum_ty = Ty::BigEnum { arity, ty: &Ty::Bool };
+    let mut patterns = vec![];
+    for i in 0..arity {
+        patterns.push(pat!(enum_ty; Variant.i));
+    }
+    patterns.push(pat!(enum_ty; _));
+    patterns
+}
+
+#[test]
+fn test_big_enum() {
+    // We try 2 branches per variant.
+    assert_complexity(big_enum(20), 40);
+}
diff --git a/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
new file mode 100644
index 00000000000..4c6c72fa8ec
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/exhaustiveness.rs
@@ -0,0 +1,77 @@
+//! Test exhaustiveness checking.
+use common::*;
+use rustc_pattern_analysis::{
+    pat::{DeconstructedPat, WitnessPat},
+    usefulness::PlaceValidity,
+    MatchArm,
+};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns.
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<WitnessPat<Cx>> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    let report =
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+    report.non_exhaustiveness_witnesses
+}
+
+#[track_caller]
+fn assert_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
+    let witnesses = check(patterns);
+    if !witnesses.is_empty() {
+        panic!("non-exaustive match: missing {witnesses:?}");
+    }
+}
+
+#[track_caller]
+fn assert_non_exhaustive(patterns: Vec<DeconstructedPat<Cx>>) {
+    let witnesses = check(patterns);
+    assert!(!witnesses.is_empty())
+}
+
+#[test]
+fn test_int_ranges() {
+    let ty = Ty::U8;
+    assert_exhaustive(pats!(ty;
+        0..=255,
+    ));
+    assert_exhaustive(pats!(ty;
+        0..,
+    ));
+    assert_non_exhaustive(pats!(ty;
+        0..255,
+    ));
+    assert_exhaustive(pats!(ty;
+        0..255,
+        255,
+    ));
+    assert_exhaustive(pats!(ty;
+        ..10,
+        10..
+    ));
+}
+
+#[test]
+fn test_nested() {
+    let ty = Ty::BigStruct { arity: 2, ty: &Ty::BigEnum { arity: 2, ty: &Ty::Bool } };
+    assert_non_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+    ));
+    assert_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(Variant.1, _),
+    ));
+    assert_non_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(_, Variant.0),
+    ));
+    assert_exhaustive(pats!(ty;
+        Struct(Variant.0, _),
+        Struct(_, Variant.0),
+        Struct(Variant.1, Variant.1),
+    ));
+}
diff --git a/compiler/rustc_pattern_analysis/tests/intersection.rs b/compiler/rustc_pattern_analysis/tests/intersection.rs
new file mode 100644
index 00000000000..4d8a21506d7
--- /dev/null
+++ b/compiler/rustc_pattern_analysis/tests/intersection.rs
@@ -0,0 +1,69 @@
+//! Test the computation of arm intersections.
+use common::*;
+use rustc_pattern_analysis::{pat::DeconstructedPat, usefulness::PlaceValidity, MatchArm};
+
+#[macro_use]
+mod common;
+
+/// Analyze a match made of these patterns and returns the computed arm intersections.
+fn check(patterns: Vec<DeconstructedPat<Cx>>) -> Vec<Vec<usize>> {
+    let ty = *patterns[0].ty();
+    let arms: Vec<_> =
+        patterns.iter().map(|pat| MatchArm { pat, has_guard: false, arm_data: () }).collect();
+    let report =
+        compute_match_usefulness(arms.as_slice(), ty, PlaceValidity::ValidOnly, None).unwrap();
+    report.arm_intersections.into_iter().map(|bitset| bitset.iter().collect()).collect()
+}
+
+#[track_caller]
+fn assert_intersects(patterns: Vec<DeconstructedPat<Cx>>, intersects: &[&[usize]]) {
+    let computed_intersects = check(patterns);
+    assert_eq!(computed_intersects, intersects);
+}
+
+#[test]
+fn test_int_ranges() {
+    let ty = Ty::U8;
+    assert_intersects(
+        pats!(ty;
+            0..=100,
+            100..,
+        ),
+        &[&[], &[0]],
+    );
+    assert_intersects(
+        pats!(ty;
+            0..=101,
+            100..,
+        ),
+        &[&[], &[0]],
+    );
+    assert_intersects(
+        pats!(ty;
+            0..100,
+            100..,
+        ),
+        &[&[], &[]],
+    );
+}
+
+#[test]
+fn test_nested() {
+    let ty = Ty::Tuple(&[Ty::Bool; 2]);
+    assert_intersects(
+        pats!(ty;
+            (true, true),
+            (true, _),
+            (_, true),
+        ),
+        &[&[], &[0], &[0, 1]],
+    );
+    // Here we shortcut because `(true, true)` is irrelevant, so we fail to detect the intersection.
+    assert_intersects(
+        pats!(ty;
+            (true, _),
+            (_, true),
+        ),
+        &[&[], &[]],
+    );
+}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 073982ca5c3..c73fdd59609 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1696,7 +1696,7 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         }
     }
 
-    for id in module.items() {
+    for id in module.free_items() {
         if let ItemKind::Impl(i) = tcx.hir().item(id).kind {
             if let Some(item) = i.of_trait {
                 let trait_ref = tcx.impl_trait_ref(id.owner_id.def_id).unwrap();
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 1b8f2fc005c..bb4294fbcfb 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1592,18 +1592,23 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
         match (res, source) {
             (
-                Res::Def(DefKind::Macro(MacroKind::Bang), _),
+                Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
                 PathSource::Expr(Some(Expr {
                     kind: ExprKind::Index(..) | ExprKind::Call(..), ..
                 }))
                 | PathSource::Struct,
             ) => {
+                // Don't suggest macro if it's unstable.
+                let suggestable = def_id.is_local()
+                    || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable());
+
                 err.span_label(span, fallback_label.to_string());
 
                 // Don't suggest `!` for a macro invocation if there are generic args
                 if path
                     .last()
                     .is_some_and(|segment| !segment.has_generic_args && !segment.has_lifetime_args)
+                    && suggestable
                 {
                     err.span_suggestion_verbose(
                         span.shrink_to_hi(),
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index e6eb1a3e83c..a88ae268e27 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -22,7 +22,7 @@ use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHa
 use rustc_target::abi::Align;
 use rustc_target::spec::LinkSelfContainedComponents;
 use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo};
-use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
+use rustc_target::spec::{Target, TargetTriple, TARGETS};
 use std::collections::btree_map::{
     Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
 };
@@ -1549,34 +1549,25 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
     user_cfg
 }
 
-pub fn build_target_config(
-    early_dcx: &EarlyDiagCtxt,
-    opts: &Options,
-    target_override: Option<Target>,
-    sysroot: &Path,
-) -> Target {
-    let target_result = target_override.map_or_else(
-        || Target::search(&opts.target_triple, sysroot),
-        |t| Ok((t, TargetWarnings::empty())),
-    );
-    let (target, target_warnings) = target_result.unwrap_or_else(|e| {
-        early_dcx.early_fatal(format!(
+pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target {
+    match Target::search(&opts.target_triple, sysroot) {
+        Ok((target, warnings)) => {
+            for warning in warnings.warning_messages() {
+                early_dcx.early_warn(warning)
+            }
+            if !matches!(target.pointer_width, 16 | 32 | 64) {
+                early_dcx.early_fatal(format!(
+                    "target specification was invalid: unrecognized target-pointer-width {}",
+                    target.pointer_width
+                ))
+            }
+            target
+        }
+        Err(e) => early_dcx.early_fatal(format!(
             "Error loading target specification: {e}. \
-                 Run `rustc --print target-list` for a list of built-in targets"
-        ))
-    });
-    for warning in target_warnings.warning_messages() {
-        early_dcx.early_warn(warning)
-    }
-
-    if !matches!(target.pointer_width, 16 | 32 | 64) {
-        early_dcx.early_fatal(format!(
-            "target specification was invalid: unrecognized target-pointer-width {}",
-            target.pointer_width
-        ))
+                     Run `rustc --print target-list` for a list of built-in targets"
+        )),
     }
-
-    target
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 9c94fd7027f..e6d82d6fab3 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1008,7 +1008,7 @@ pub fn build_session(
     fluent_resources: Vec<&'static str>,
     driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
-    target_cfg: Target,
+    target: Target,
     sysroot: PathBuf,
     cfg_version: &'static str,
     ice_file: Option<PathBuf>,
@@ -1036,7 +1036,7 @@ pub fn build_session(
 
     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
     let hash_kind = sopts.unstable_opts.src_hash_algorithm.unwrap_or_else(|| {
-        if target_cfg.is_like_msvc {
+        if target.is_like_msvc {
             SourceFileHashAlgorithm::Sha256
         } else {
             SourceFileHashAlgorithm::Md5
@@ -1117,11 +1117,10 @@ pub fn build_session(
         _ => CtfeBacktrace::Disabled,
     });
 
-    let asm_arch =
-        if target_cfg.allow_asm { InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None };
+    let asm_arch = if target.allow_asm { InlineAsmArch::from_str(&target.arch).ok() } else { None };
 
     let sess = Session {
-        target: target_cfg,
+        target,
         host,
         opts: sopts,
         host_tlib_path,
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 6766080a54f..f0fb87fe83c 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -25,7 +25,7 @@ pub fn report_symbol_names(tcx: TyCtxt<'_>) {
         let mut symbol_names = SymbolNamesTest { tcx };
         let crate_items = tcx.hir_crate_items(());
 
-        for id in crate_items.items() {
+        for id in crate_items.free_items() {
             symbol_names.process_attrs(id.owner_id.def_id);
         }
 
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 896f208f560..966da2c5eda 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2092,6 +2092,9 @@ pub struct TargetOptions {
     /// compiling `rustc` will be used instead (or llvm if it is not set).
     ///
     /// N.B. when *using* the compiler, backend can always be overridden with `-Zcodegen-backend`.
+    ///
+    /// This was added by WaffleLapkin in #116793. The motivation is a rustc fork that requires a
+    /// custom codegen backend for a particular target.
     pub default_codegen_backend: Option<StaticCow<str>>,
 
     /// Whether to generate trap instructions in places where optimization would
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 0dcba0e05f7..f96bd985237 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -19,6 +19,9 @@ trait_selection_closure_kind_mismatch = expected a closure that implements the `
 
 trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here
 
+trait_selection_disallowed_positional_argument = positional format arguments are not allowed here
+    .help = only named format arguments with the name of one of the generic types are allowed in this context
+
 trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
 
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
@@ -30,6 +33,9 @@ trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to p
 
 trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
 
+trait_selection_invalid_format_specifier = invalid format specifier
+    .help = no format specifier are supported in this position
+
 trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
     .label = invalid on-clause here
 
@@ -60,3 +66,6 @@ trait_selection_unable_to_construct_constant_value = unable to construct a const
 
 trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}`
     .help = expect either a generic argument name or {"`{Self}`"} as format argument
+
+trait_selection_wrapped_parser_error = {$description}
+    .label = {$label}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 745ddfc08af..5fccc769785 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -367,6 +367,23 @@ pub struct UnknownFormatParameterForOnUnimplementedAttr {
     trait_name: Symbol,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_disallowed_positional_argument)]
+#[help]
+pub struct DisallowedPositionalArgument;
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_invalid_format_specifier)]
+#[help]
+pub struct InvalidFormatSpecifier;
+
+#[derive(LintDiagnostic)]
+#[diag(trait_selection_wrapped_parser_error)]
+pub struct WrappedParserError {
+    description: String,
+    label: String,
+}
+
 impl<'tcx> OnUnimplementedDirective {
     fn parse(
         tcx: TyCtxt<'tcx>,
@@ -758,64 +775,108 @@ impl<'tcx> OnUnimplementedFormatString {
         let trait_name = tcx.item_name(trait_def_id);
         let generics = tcx.generics_of(item_def_id);
         let s = self.symbol.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
         let mut result = Ok(());
-        for token in parser {
+        for token in &mut parser {
             match token {
                 Piece::String(_) => (), // Normal string, no need to check it
-                Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s) => {
-                        match Symbol::intern(s) {
-                            // `{ThisTraitsName}` is allowed
-                            s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
-                            s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
-                                && !self.is_diagnostic_namespace_variant =>
-                            {
-                                ()
-                            }
-                            // So is `{A}` if A is a type parameter
-                            s if generics.params.iter().any(|param| param.name == s) => (),
-                            s => {
-                                if self.is_diagnostic_namespace_variant {
-                                    tcx.emit_node_span_lint(
-                                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                                        tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                                        self.span,
-                                        UnknownFormatParameterForOnUnimplementedAttr {
-                                            argument_name: s,
-                                            trait_name,
-                                        },
-                                    );
-                                } else {
-                                    result = Err(struct_span_code_err!(
-                                        tcx.dcx(),
-                                        self.span,
-                                        E0230,
-                                        "there is no parameter `{}` on {}",
-                                        s,
-                                        if trait_def_id == item_def_id {
-                                            format!("trait `{trait_name}`")
-                                        } else {
-                                            "impl".to_string()
-                                        }
-                                    )
-                                    .emit());
+                Piece::NextArgument(a) => {
+                    let format_spec = a.format;
+                    if self.is_diagnostic_namespace_variant
+                        && (format_spec.ty_span.is_some()
+                            || format_spec.width_span.is_some()
+                            || format_spec.precision_span.is_some()
+                            || format_spec.fill_span.is_some())
+                    {
+                        tcx.emit_node_span_lint(
+                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                            self.span,
+                            InvalidFormatSpecifier,
+                        );
+                    }
+                    match a.position {
+                        Position::ArgumentNamed(s) => {
+                            match Symbol::intern(s) {
+                                // `{ThisTraitsName}` is allowed
+                                s if s == trait_name && !self.is_diagnostic_namespace_variant => (),
+                                s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
+                                    && !self.is_diagnostic_namespace_variant =>
+                                {
+                                    ()
+                                }
+                                // So is `{A}` if A is a type parameter
+                                s if generics.params.iter().any(|param| param.name == s) => (),
+                                s => {
+                                    if self.is_diagnostic_namespace_variant {
+                                        tcx.emit_node_span_lint(
+                                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                                            self.span,
+                                            UnknownFormatParameterForOnUnimplementedAttr {
+                                                argument_name: s,
+                                                trait_name,
+                                            },
+                                        );
+                                    } else {
+                                        result = Err(struct_span_code_err!(
+                                            tcx.dcx(),
+                                            self.span,
+                                            E0230,
+                                            "there is no parameter `{}` on {}",
+                                            s,
+                                            if trait_def_id == item_def_id {
+                                                format!("trait `{trait_name}`")
+                                            } else {
+                                                "impl".to_string()
+                                            }
+                                        )
+                                        .emit());
+                                    }
                                 }
                             }
                         }
+                        // `{:1}` and `{}` are not to be used
+                        Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
+                            if self.is_diagnostic_namespace_variant {
+                                tcx.emit_node_span_lint(
+                                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                                    self.span,
+                                    DisallowedPositionalArgument,
+                                );
+                            } else {
+                                let reported = struct_span_code_err!(
+                                    tcx.dcx(),
+                                    self.span,
+                                    E0231,
+                                    "only named generic parameters are allowed"
+                                )
+                                .emit();
+                                result = Err(reported);
+                            }
+                        }
                     }
-                    // `{:1}` and `{}` are not to be used
-                    Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
-                        let reported = struct_span_code_err!(
-                            tcx.dcx(),
-                            self.span,
-                            E0231,
-                            "only named generic parameters are allowed"
-                        )
-                        .emit();
-                        result = Err(reported);
-                    }
-                },
+                }
+            }
+        }
+        // we cannot return errors from processing the format string as hard error here
+        // as the diagnostic namespace gurantees that malformed input cannot cause an error
+        //
+        // if we encounter any error while processing we nevertheless want to show it as warning
+        // so that users are aware that something is not correct
+        for e in parser.errors {
+            if self.is_diagnostic_namespace_variant {
+                tcx.emit_node_span_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
+                    self.span,
+                    WrappedParserError { description: e.description, label: e.label },
+                );
+            } else {
+                let reported =
+                    struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
+                result = Err(reported);
             }
         }
 
@@ -853,9 +914,9 @@ impl<'tcx> OnUnimplementedFormatString {
         let empty_string = String::new();
 
         let s = self.symbol.as_str();
-        let parser = Parser::new(s, None, None, false, ParseMode::Format);
+        let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
         let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
-        parser
+        let constructed_message = (&mut parser)
             .map(|p| match p {
                 Piece::String(s) => s.to_owned(),
                 Piece::NextArgument(a) => match a.position {
@@ -895,9 +956,29 @@ impl<'tcx> OnUnimplementedFormatString {
                             }
                         }
                     }
+                    Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => {
+                        String::from("{}")
+                    }
+                    Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => {
+                        format!("{{{idx}}}")
+                    }
                     _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol),
                 },
             })
-            .collect()
+            .collect();
+        // we cannot return errors from processing the format string as hard error here
+        // as the diagnostic namespace gurantees that malformed input cannot cause an error
+        //
+        // if we encounter any error while processing the format string
+        // we don't want to show the potentially half assembled formated string,
+        // therefore we fall back to just showing the input string in this case
+        //
+        // The actual parser errors are emitted earlier
+        // as lint warnings in OnUnimplementedFormatString::verify
+        if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() {
+            String::from(s)
+        } else {
+            constructed_message
+        }
     }
 }
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index ebcaa626bd3..a78842c8f8d 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1714,6 +1714,18 @@ pub(crate) mod builtin {
         builtin # type_ascribe($expr, $ty)
     }
 
+    #[cfg(not(bootstrap))]
+    /// Unstable placeholder for deref patterns.
+    #[allow_internal_unstable(builtin_syntax)]
+    #[unstable(
+        feature = "deref_patterns",
+        issue = "87121",
+        reason = "placeholder syntax for deref patterns"
+    )]
+    pub macro deref($pat:pat) {
+        builtin # deref($pat)
+    }
+
     /// Unstable implementation detail of the `rustc` compiler, do not use.
     #[rustc_builtin_macro]
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 10525a16f3a..29f73bb4942 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -103,3 +103,11 @@ pub use crate::macros::builtin::cfg_eval;
     reason = "placeholder syntax for type ascription"
 )]
 pub use crate::macros::builtin::type_ascribe;
+
+#[cfg(not(bootstrap))]
+#[unstable(
+    feature = "deref_patterns",
+    issue = "87121",
+    reason = "placeholder syntax for deref patterns"
+)]
+pub use crate::macros::builtin::deref;
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 7a7a7737635..36fa4e88b5b 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -91,6 +91,15 @@ pub use core::prelude::v1::cfg_eval;
 )]
 pub use core::prelude::v1::type_ascribe;
 
+#[cfg(not(bootstrap))]
+// Do not `doc(no_inline)` either.
+#[unstable(
+    feature = "deref_patterns",
+    issue = "87121",
+    reason = "placeholder syntax for deref patterns"
+)]
+pub use core::prelude::v1::deref;
+
 // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated
 // rather than glob imported because we want docs to show these re-exports as
 // pointing to within `std`.
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 365d63d9657..977b4bb45b6 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -329,6 +329,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
             elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
         ),
         PatKind::Box(p) => return name_from_pat(&*p),
+        PatKind::Deref(p) => format!("deref!({})", name_from_pat(&*p)),
         PatKind::Ref(p, _) => return name_from_pat(&*p),
         PatKind::Lit(..) => {
             warn!(
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 4e728d61b85..37442bf3e28 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -55,7 +55,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         | PatKind::Err(_) => false,
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
-        PatKind::Ref(x, _) | PatKind::Box(x) => unary_pattern(x),
+        PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) => unary_pattern(x),
         PatKind::Path(_) | PatKind::Lit(_) => true,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index c7c453b7f6e..cd61e733694 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -243,7 +243,7 @@ impl<'a> NormalizedPat<'a> {
     fn from_pat(cx: &LateContext<'_>, arena: &'a DroplessArena, pat: &'a Pat<'_>) -> Self {
         match pat.kind {
             PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
-            PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
+            PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => {
                 Self::from_pat(cx, arena, pat)
             },
             PatKind::Never => Self::Never,
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 7246214f9bf..d4dd31e1178 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -242,6 +242,8 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
             |k| matches!(k, Box(_)),
             |k| always_pat!(k, Box(p) => p),
         ),
+        // FIXME(deref_patterns): Should we merge patterns here?
+        Deref(_) => false,
         // Transform `&mut x | ... | &mut y` into `&mut (x | y)`.
         Ref(target, Mutability::Mut) => extend_with_matching(
             target, start, alternatives,
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 187bfda129c..5319915b2ea 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -689,6 +689,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 kind!("Box({pat})");
                 self.pat(pat);
             },
+            PatKind::Deref(pat) => {
+                bind!(self, pat);
+                kind!("Deref({pat})");
+                self.pat(pat);
+            },
             PatKind::Ref(pat, muta) => {
                 bind!(self, pat);
                 kind!("Ref({pat}, Mutability::{muta:?})");
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 162bf24d85d..7a4eba9790e 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -955,6 +955,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
             },
             PatKind::Box(pat) => self.hash_pat(pat),
+            PatKind::Deref(pat) => self.hash_pat(pat),
             PatKind::Lit(expr) => self.hash_expr(expr),
             PatKind::Or(pats) => {
                 for pat in pats {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index a38db0ebec0..b4cc747e0e6 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1678,7 +1678,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
     match pat.kind {
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
-        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
+        PatKind::Box(pat) | PatKind::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 7f576279432..47b48468a24 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -55,9 +55,10 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
         ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
             path.segments.len() <= 1 && subpats.len() <= 1
         }
-        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
-            is_short_pattern_inner(&*p)
-        }
+        ast::PatKind::Box(ref p)
+        | PatKind::Deref(ref p)
+        | ast::PatKind::Ref(ref p, _)
+        | ast::PatKind::Paren(ref p) => is_short_pattern_inner(&*p),
         PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)),
     }
 }
@@ -277,6 +278,7 @@ impl Rewrite for Pat {
                 .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
                 .map(|inner_pat| format!("({})", inner_pat)),
             PatKind::Err(_) => None,
+            PatKind::Deref(_) => None,
         }
     }
 }
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 2e3bf70e144..e67ec8690f8 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -68,7 +68,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
             let mut bodies = Vec::new();
 
             let crate_items = tcx.hir_crate_items(());
-            for id in crate_items.items() {
+            for id in crate_items.free_items() {
                 if matches!(tcx.def_kind(id.owner_id), DefKind::Fn) {
                     bodies.push(id.owner_id);
                 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
new file mode 100644
index 00000000000..8d8917fd319
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
@@ -0,0 +1,45 @@
+#[diagnostic::on_unimplemented(message = "{{Test } thing")]
+//~^WARN unmatched `}` found
+//~|WARN unmatched `}` found
+trait ImportantTrait1 {}
+
+#[diagnostic::on_unimplemented(message = "Test {}")]
+//~^WARN positional format arguments are not allowed here
+//~|WARN positional format arguments are not allowed here
+trait ImportantTrait2 {}
+
+#[diagnostic::on_unimplemented(message = "Test {1:}")]
+//~^WARN positional format arguments are not allowed here
+//~|WARN positional format arguments are not allowed here
+trait ImportantTrait3 {}
+
+#[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+//~^WARN invalid format specifier
+//~|WARN invalid format specifier
+trait ImportantTrait4 {}
+
+#[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+//~^WARN expected `'}'`, found `'!'`
+//~|WARN expected `'}'`, found `'!'`
+//~|WARN unmatched `}` found
+//~|WARN unmatched `}` found
+trait ImportantTrait5 {}
+
+fn check_1(_: impl ImportantTrait1) {}
+fn check_2(_: impl ImportantTrait2) {}
+fn check_3(_: impl ImportantTrait3) {}
+fn check_4(_: impl ImportantTrait4) {}
+fn check_5(_: impl ImportantTrait5) {}
+
+fn main() {
+    check_1(());
+    //~^ERROR {{Test } thing
+    check_2(());
+    //~^ERROR Test {}
+    check_3(());
+    //~^ERROR Test {1}
+    check_4(());
+    //~^ERROR Test ()
+    check_5(());
+    //~^ERROR Test {Self:!}
+}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
new file mode 100644
index 00000000000..932e81ca48e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -0,0 +1,193 @@
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:1:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:6:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {}")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:11:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:16:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: no format specifier are supported in this position
+
+warning: expected `'}'`, found `'!'`
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:1:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: {{Test } thing
+  --> $DIR/broken_format.rs:35:13
+   |
+LL |     check_1(());
+   |     ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:4:1
+   |
+LL | trait ImportantTrait1 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_1`
+  --> $DIR/broken_format.rs:28:20
+   |
+LL | fn check_1(_: impl ImportantTrait1) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_1`
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:6:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {}")]
+   |                                ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {}
+  --> $DIR/broken_format.rs:37:13
+   |
+LL |     check_2(());
+   |     ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:9:1
+   |
+LL | trait ImportantTrait2 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_2`
+  --> $DIR/broken_format.rs:29:20
+   |
+LL | fn check_2(_: impl ImportantTrait2) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_2`
+
+warning: positional format arguments are not allowed here
+  --> $DIR/broken_format.rs:11:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: only named format arguments with the name of one of the generic types are allowed in this context
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {1}
+  --> $DIR/broken_format.rs:39:13
+   |
+LL |     check_3(());
+   |     ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:14:1
+   |
+LL | trait ImportantTrait3 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_3`
+  --> $DIR/broken_format.rs:30:20
+   |
+LL | fn check_3(_: impl ImportantTrait3) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_3`
+
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:16:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: no format specifier are supported in this position
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test ()
+  --> $DIR/broken_format.rs:41:13
+   |
+LL |     check_4(());
+   |     ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:19:1
+   |
+LL | trait ImportantTrait4 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_4`
+  --> $DIR/broken_format.rs:31:20
+   |
+LL | fn check_4(_: impl ImportantTrait4) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_4`
+
+warning: expected `'}'`, found `'!'`
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+warning: unmatched `}` found
+  --> $DIR/broken_format.rs:21:32
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test {Self:!}
+  --> $DIR/broken_format.rs:43:13
+   |
+LL |     check_5(());
+   |     ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:26:1
+   |
+LL | trait ImportantTrait5 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_5`
+  --> $DIR/broken_format.rs:32:20
+   |
+LL | fn check_5(_: impl ImportantTrait5) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_5`
+
+error: aborting due to 5 previous errors; 12 warnings emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs
new file mode 100644
index 00000000000..cedbd1d6686
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs
@@ -0,0 +1,12 @@
+macro_rules! mac {
+    ($attr_item: meta) => {
+        #[cfg($attr_item)]
+        //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        struct S;
+    }
+}
+
+mac!(an(arbitrary token stream));
+
+fn main() {}
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
new file mode 100644
index 00000000000..a543bcb692e
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
@@ -0,0 +1,25 @@
+error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+  --> $DIR/attr-bad-meta-4.rs:3:15
+   |
+LL |         #[cfg($attr_item)]
+   |               ^^^^^^^^^^
+...
+LL | mac!(an(arbitrary token stream));
+   | -------------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+  --> $DIR/attr-bad-meta-4.rs:3:15
+   |
+LL |         #[cfg($attr_item)]
+   |               ^^^^^^^^^^
+...
+LL | mac!(an(arbitrary token stream));
+   | -------------------------------- in this macro invocation
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+   = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs
index 20577abe485..ead6dcdbaf0 100644
--- a/tests/ui/pattern/deref-patterns/typeck.rs
+++ b/tests/ui/pattern/deref-patterns/typeck.rs
@@ -7,19 +7,19 @@ use std::rc::Rc;
 fn main() {
     let vec: Vec<u32> = Vec::new();
     match vec {
-        box [..] => {}
+        deref!([..]) => {}
         _ => {}
     }
     match Box::new(true) {
-        box true => {}
+        deref!(true) => {}
         _ => {}
     }
     match &Box::new(true) {
-        box true => {}
+        deref!(true) => {}
         _ => {}
     }
     match &Rc::new(0) {
-        box (1..) => {}
+        deref!(1..) => {}
         _ => {}
     }
     // FIXME(deref_patterns): fails to typecheck because `"foo"` has type &str but deref creates a
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs
new file mode 100644
index 00000000000..ef9fe604ea7
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.rs
@@ -0,0 +1,25 @@
+//! This test used to ICE because, while an error was emitted,
+//! we still tried to remap generic params used in the hidden type
+//! to the ones of the opaque type definition.
+
+//@ edition: 2021
+
+#![feature(type_alias_impl_trait)]
+use std::future::Future;
+
+type FutNothing<'a> = impl 'a + Future<Output = ()>;
+//~^ ERROR: unconstrained opaque type
+
+async fn operation(_: &mut ()) -> () {
+    //~^ ERROR: concrete type differs from previous
+    call(operation).await
+}
+
+async fn call<F>(_f: F)
+where
+    for<'any> F: FnMut(&'any mut ()) -> FutNothing<'any>,
+{
+    //~^ ERROR: expected generic lifetime parameter, found `'any`
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr
new file mode 100644
index 00000000000..d7a0452727e
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/hkl_forbidden4.stderr
@@ -0,0 +1,34 @@
+error: unconstrained opaque type
+  --> $DIR/hkl_forbidden4.rs:10:23
+   |
+LL | type FutNothing<'a> = impl 'a + Future<Output = ()>;
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `FutNothing` must be used in combination with a concrete type within the same module
+
+error: concrete type differs from previous defining opaque type use
+  --> $DIR/hkl_forbidden4.rs:13:1
+   |
+LL | async fn operation(_: &mut ()) -> () {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `FutNothing<'_>`, got `{async fn body@$DIR/hkl_forbidden4.rs:13:38: 16:2}`
+   |
+note: previous use here
+  --> $DIR/hkl_forbidden4.rs:15:5
+   |
+LL |     call(operation).await
+   |     ^^^^^^^^^^^^^^^
+
+error[E0792]: expected generic lifetime parameter, found `'any`
+  --> $DIR/hkl_forbidden4.rs:21:1
+   |
+LL |   type FutNothing<'a> = impl 'a + Future<Output = ()>;
+   |                   -- this generic parameter must be used with a generic lifetime parameter
+...
+LL | / {
+LL | |
+LL | | }
+   | |_^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0792`.
diff --git a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
index 1470c32d7de..5f22c781345 100644
--- a/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
+++ b/tests/ui/unboxed-closures/unboxed-closures-type-mismatch-closure-from-another-scope.stderr
@@ -26,11 +26,11 @@ note: closure parameter defined here
 LL |         let mut closure = expect_sig(|p, y| *p = y);
    |                                       ^
 
-error[E0425]: cannot find function `deref` in this scope
+error[E0423]: expected function, found macro `deref`
   --> $DIR/unboxed-closures-type-mismatch-closure-from-another-scope.rs:13:5
    |
 LL |     deref(p);
-   |     ^^^^^ not found in this scope
+   |     ^^^^^ not a function
    |
 help: use the `.` operator to call the method `Deref::deref` on `&&()`
    |
@@ -40,5 +40,5 @@ LL +     p.deref();
 
 error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0308, E0425.
+Some errors have detailed explanations: E0308, E0423, E0425.
 For more information about an error, try `rustc --explain E0308`.