about summary refs log tree commit diff
path: root/compiler/rustc_builtin_macros/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_builtin_macros/src')
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs128
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs26
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs76
-rw-r--r--compiler/rustc_builtin_macros/src/cmdline_attrs.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/compile_error.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs88
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs207
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs42
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs25
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs11
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs28
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs92
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs229
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/ty.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/mod.rs30
-rw-r--r--compiler/rustc_builtin_macros/src/edition_panic.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs132
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs95
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs172
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/log_syntax.rs10
-rw-r--r--compiler/rustc_builtin_macros/src/pattern_type.rs29
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs258
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs17
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs9
-rw-r--r--compiler/rustc_builtin_macros/src/trace_macros.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/type_ascribe.rs35
-rw-r--r--compiler/rustc_builtin_macros/src/util.rs200
43 files changed, 1292 insertions, 905 deletions
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index bc94e0b972b..4721e74b955 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -3,13 +3,13 @@ use crate::util::check_builtin_macro_attribute;
 
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
-use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Safety, Stmt, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand(
+pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
     meta_item: &ast::MetaItem,
@@ -78,7 +78,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
     let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
     let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
     let decl = cx.fn_decl(params, never);
-    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() };
     let sig = FnSig { decl, header, span: span };
 
     let body = Some(cx.block_expr(call));
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 0b2e63b403b..1a7961bf70c 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,23 +1,24 @@
+use crate::errors;
+use crate::util::expr_to_spanned_string;
+use ast::token::IdentIsRaw;
+use lint::BuiltinLintDiag;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::PResult;
-use rustc_expand::base::{self, *};
+use rustc_expand::base::*;
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_parse::parser::Parser;
 use rustc_parse_format as parse;
 use rustc_session::lint;
-use rustc_session::parse::ParseSess;
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{InnerSpan, Span};
+use rustc_span::{ErrorGuaranteed, InnerSpan, Span};
 use rustc_target::asm::InlineAsmArch;
 use smallvec::smallvec;
 
-use crate::errors;
-
 pub struct AsmArgs {
     pub templates: Vec<P<ast::Expr>>,
     pub operands: Vec<(ast::InlineAsmOperand, Span)>,
@@ -29,25 +30,23 @@ pub struct AsmArgs {
 }
 
 fn parse_args<'a>(
-    ecx: &mut ExtCtxt<'a>,
+    ecx: &ExtCtxt<'a>,
     sp: Span,
     tts: TokenStream,
     is_global_asm: bool,
 ) -> PResult<'a, AsmArgs> {
     let mut p = ecx.new_parser_from_tts(tts);
-    let sess = &ecx.sess.parse_sess;
-    parse_asm_args(&mut p, sess, sp, is_global_asm)
+    parse_asm_args(&mut p, sp, is_global_asm)
 }
 
 // Primarily public for rustfmt consumption.
 // Internal consumers should continue to leverage `expand_asm`/`expand__global_asm`
 pub fn parse_asm_args<'a>(
     p: &mut Parser<'a>,
-    sess: &'a ParseSess,
     sp: Span,
     is_global_asm: bool,
 ) -> PResult<'a, AsmArgs> {
-    let dcx = &sess.dcx;
+    let dcx = &p.psess.dcx;
 
     if p.token == token::Eof {
         return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
@@ -166,6 +165,9 @@ pub fn parse_asm_args<'a>(
                 path: path.clone(),
             };
             ast::InlineAsmOperand::Sym { sym }
+        } else if !is_global_asm && p.eat_keyword(sym::label) {
+            let block = p.parse_block()?;
+            ast::InlineAsmOperand::Label { block }
         } else if allow_templates {
             let template = p.parse_expr()?;
             // If it can't possibly expand to a string, provide diagnostics here to include other
@@ -188,7 +190,7 @@ pub fn parse_asm_args<'a>(
             args.templates.push(template);
             continue;
         } else {
-            return p.unexpected();
+            p.unexpected_any()?
         };
 
         allow_templates = false;
@@ -242,6 +244,7 @@ pub fn parse_asm_args<'a>(
     let mut have_real_output = false;
     let mut outputs_sp = vec![];
     let mut regclass_outputs = vec![];
+    let mut labels_sp = vec![];
     for (op, op_sp) in &args.operands {
         match op {
             ast::InlineAsmOperand::Out { reg, expr, .. }
@@ -259,6 +262,9 @@ pub fn parse_asm_args<'a>(
                     regclass_outputs.push(*op_sp);
                 }
             }
+            ast::InlineAsmOperand::Label { .. } => {
+                labels_sp.push(*op_sp);
+            }
             _ => {}
         }
     }
@@ -270,6 +276,9 @@ pub fn parse_asm_args<'a>(
         // Bail out now since this is likely to confuse MIR
         return Err(err);
     }
+    if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
+        dcx.emit_err(errors::AsmMayUnwind { labels_sp });
+    }
 
     if args.clobber_abis.len() > 0 {
         if is_global_asm {
@@ -295,10 +304,10 @@ pub fn parse_asm_args<'a>(
 ///
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the suggestion will be incorrect.
-fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
+fn err_duplicate_option(p: &Parser<'_>, symbol: Symbol, span: Span) {
     // Tool-only output
     let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
-    p.sess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
+    p.psess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
 }
 
 /// Try to set the provided option in the provided `AsmArgs`.
@@ -307,7 +316,7 @@ fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
 /// This function must be called immediately after the option token is parsed.
 /// Otherwise, the error will not point to the correct spot.
 fn try_set_option<'a>(
-    p: &mut Parser<'a>,
+    p: &Parser<'a>,
     args: &mut AsmArgs,
     symbol: Symbol,
     option: ast::InlineAsmOptions,
@@ -370,7 +379,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
     p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
 
     if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
-        return Err(p.sess.dcx.create_err(errors::NonABI { span: p.token.span }));
+        return Err(p.psess.dcx.create_err(errors::NonABI { span: p.token.span }));
     }
 
     let mut new_abis = Vec::new();
@@ -381,7 +390,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
             }
             Err(opt_lit) => {
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-                let mut err = p.sess.dcx.struct_span_err(span, "expected string literal");
+                let mut err = p.psess.dcx.struct_span_err(span, "expected string literal");
                 err.span_label(span, "not a string literal");
                 return Err(err);
             }
@@ -416,7 +425,7 @@ fn parse_reg<'a>(
 ) -> PResult<'a, ast::InlineAsmRegOrRegClass> {
     p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
     let result = match p.token.uninterpolate().kind {
-        token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name),
+        token::Ident(name, IdentIsRaw::No) => ast::InlineAsmRegOrRegClass::RegClass(name),
         token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => {
             *explicit_reg = true;
             ast::InlineAsmRegOrRegClass::Reg(symbol)
@@ -432,7 +441,10 @@ fn parse_reg<'a>(
     Ok(result)
 }
 
-fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::InlineAsm> {
+fn expand_preparsed_asm(
+    ecx: &mut ExtCtxt<'_>,
+    args: AsmArgs,
+) -> ExpandResult<Result<ast::InlineAsm, ErrorGuaranteed>, ()> {
     let mut template = vec![];
     // Register operands are implicitly used since they are not allowed to be
     // referenced in the template string.
@@ -454,16 +466,20 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
 
         let msg = "asm template must be a string literal";
         let template_sp = template_expr.span;
-        let (template_str, template_style, template_span) =
-            match expr_to_spanned_string(ecx, template_expr, msg) {
+        let (template_str, template_style, template_span) = {
+            let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
                 Ok(template_part) => template_part,
                 Err(err) => {
-                    if let Some((err, _)) = err {
-                        err.emit();
-                    }
-                    return None;
+                    return ExpandResult::Ready(Err(match err {
+                        Ok((err, _)) => err.emit(),
+                        Err(guar) => guar,
+                    }));
                 }
-            };
+            }
+        };
 
         let str_style = match template_style {
             ast::StrStyle::Cooked => None,
@@ -494,19 +510,19 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             };
 
             if template_str.contains(".intel_syntax") {
-                ecx.parse_sess().buffer_lint(
+                ecx.psess().buffer_lint(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".intel_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.intel_syntax`, Intel syntax is the default",
+                    BuiltinLintDiag::AvoidUsingIntelSyntax,
                 );
             }
             if template_str.contains(".att_syntax") {
-                ecx.parse_sess().buffer_lint(
+                ecx.psess().buffer_lint(
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".att_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
+                    BuiltinLintDiag::AvoidUsingAttSyntax,
                 );
             }
         }
@@ -550,8 +566,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                 let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
                 e.span_label(err_sp, label);
             }
-            e.emit();
-            return None;
+            let guar = e.emit();
+            return ExpandResult::Ready(Err(guar));
         }
 
         curarg = parser.curarg;
@@ -718,52 +734,57 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
         }
     }
 
-    Some(ast::InlineAsm {
+    ExpandResult::Ready(Ok(ast::InlineAsm {
         template,
         template_strs: template_strs.into_boxed_slice(),
         operands: args.operands,
         clobber_abis: args.clobber_abis,
         options: args.options,
         line_spans,
-    })
+    }))
 }
 
 pub(super) fn expand_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    match parse_args(ecx, sp, tts, false) {
+) -> MacroExpanderResult<'cx> {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, false) {
         Ok(args) => {
-            let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
-                P(ast::Expr {
+            let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
+                return ExpandResult::Retry(());
+            };
+            let expr = match mac {
+                Ok(inline_asm) => P(ast::Expr {
                     id: ast::DUMMY_NODE_ID,
                     kind: ast::ExprKind::InlineAsm(P(inline_asm)),
                     span: sp,
                     attrs: ast::AttrVec::new(),
                     tokens: None,
-                })
-            } else {
-                DummyResult::raw_expr(sp, true)
+                }),
+                Err(guar) => DummyResult::raw_expr(sp, Some(guar)),
             };
             MacEager::expr(expr)
         }
         Err(err) => {
-            err.emit();
-            DummyResult::any(sp)
+            let guar = err.emit();
+            DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
 pub(super) fn expand_global_asm<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    match parse_args(ecx, sp, tts, true) {
+) -> MacroExpanderResult<'cx> {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts, true) {
         Ok(args) => {
-            if let Some(inline_asm) = expand_preparsed_asm(ecx, args) {
-                MacEager::items(smallvec![P(ast::Item {
+            let ExpandResult::Ready(mac) = expand_preparsed_asm(ecx, args) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item {
                     ident: Ident::empty(),
                     attrs: ast::AttrVec::new(),
                     id: ast::DUMMY_NODE_ID,
@@ -773,16 +794,15 @@ pub(super) fn expand_global_asm<'cx>(
                         kind: ast::VisibilityKind::Inherited,
                         tokens: None,
                     },
-                    span: ecx.with_def_site_ctxt(sp),
+                    span: sp,
                     tokens: None,
-                })])
-            } else {
-                DummyResult::any(sp)
+                })]),
+                Err(guar) => DummyResult::any(sp, guar),
             }
         }
         Err(err) => {
-            err.emit();
-            DummyResult::any(sp)
+            let guar = err.emit();
+            DummyResult::any(sp, guar)
         }
-    }
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 501d557f3ab..c75050f2701 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -9,22 +9,22 @@ use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{DelimArgs, Expr, ExprKind, MacCall, Path, PathSegment, UnOp};
 use rustc_ast_pretty::pprust;
 use rustc_errors::PResult;
-use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_parse::parser::Parser;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use thin_vec::thin_vec;
 
-pub fn expand_assert<'cx>(
+pub(crate) fn expand_assert<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     span: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) {
         Ok(assert) => assert,
         Err(err) => {
-            err.emit();
-            return DummyResult::any(span);
+            let guar = err.emit();
+            return ExpandResult::Ready(DummyResult::any(span, guar));
         }
     };
 
@@ -92,7 +92,7 @@ pub fn expand_assert<'cx>(
         expr_if_not(cx, call_site_span, cond_expr, then, None)
     };
 
-    MacEager::expr(expr)
+    ExpandResult::Ready(MacEager::expr(expr))
 }
 
 struct Assert {
@@ -111,7 +111,7 @@ fn expr_if_not(
     cx.expr_if(span, cx.expr(span, ExprKind::Unary(UnOp::Not, cond)), then, els)
 }
 
-fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
+fn parse_assert<'a>(cx: &ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PResult<'a, Assert> {
     let mut parser = cx.new_parser_from_tts(stream);
 
     if parser.token == token::Eof {
@@ -151,7 +151,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
         };
 
     if parser.token != token::Eof {
-        return parser.unexpected();
+        parser.unexpected()?;
     }
 
     Ok(Assert { cond_expr, custom_message })
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index a98ed996df6..a98cb6f0f76 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -1,7 +1,6 @@
 use rustc_ast::{
     ptr::P,
-    token,
-    token::Delimiter,
+    token::{self, Delimiter, IdentIsRaw},
     tokenstream::{DelimSpan, TokenStream, TokenTree},
     BinOpKind, BorrowKind, DelimArgs, Expr, ExprKind, ItemKind, MacCall, MethodCall, Mutability,
     Path, PathSegment, Stmt, StructRest, UnOp, UseTree, UseTreeKind, DUMMY_NODE_ID,
@@ -120,10 +119,13 @@ impl<'cx, 'a> Context<'cx, 'a> {
                 thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)],
                 ItemKind::Use(UseTree {
                     prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
-                    kind: UseTreeKind::Nested(thin_vec![
-                        nested_tree(self, sym::TryCaptureGeneric),
-                        nested_tree(self, sym::TryCapturePrintable),
-                    ]),
+                    kind: UseTreeKind::Nested {
+                        items: thin_vec![
+                            nested_tree(self, sym::TryCaptureGeneric),
+                            nested_tree(self, sym::TryCapturePrintable),
+                        ],
+                        span: self.span,
+                    },
                     span: self.span,
                 }),
             ),
@@ -150,7 +152,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
     fn build_panic(&self, expr_str: &str, panic_path: Path) -> P<Expr> {
         let escaped_expr_str = escape_to_fmt(expr_str);
         let initial = [
-            TokenTree::token_joint_hidden(
+            TokenTree::token_joint(
                 token::Literal(token::Lit {
                     kind: token::LitKind::Str,
                     symbol: Symbol::intern(&if self.fmt_string.is_empty() {
@@ -169,7 +171,10 @@ impl<'cx, 'a> Context<'cx, 'a> {
         ];
         let captures = self.capture_decls.iter().flat_map(|cap| {
             [
-                TokenTree::token_joint_hidden(token::Ident(cap.ident.name, false), cap.ident.span),
+                TokenTree::token_joint(
+                    token::Ident(cap.ident.name, IdentIsRaw::No),
+                    cap.ident.span,
+                ),
                 TokenTree::token_alone(token::Comma, self.span),
             ]
         });
@@ -242,7 +247,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
             ExprKind::Let(_, local_expr, _, _) => {
                 self.manage_cond_expr(local_expr);
             }
-            ExprKind::Match(local_expr, _) => {
+            ExprKind::Match(local_expr, ..) => {
                 self.manage_cond_expr(local_expr);
             }
             ExprKind::MethodCall(call) => {
@@ -300,7 +305,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
             | ExprKind::Closure(_)
             | ExprKind::ConstBlock(_)
             | ExprKind::Continue(_)
-            | ExprKind::Err
+            | ExprKind::Dummy
+            | ExprKind::Err(_)
             | ExprKind::Field(_, _)
             | ExprKind::ForLoop { .. }
             | ExprKind::FormatArgs(_)
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 581d390992a..827719d7944 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -8,17 +8,17 @@ use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_attr as attr;
 use rustc_errors::PResult;
-use rustc_expand::base::{self, *};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_span::Span;
 
-pub fn expand_cfg(
+pub(crate) fn expand_cfg(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
 
-    match parse_cfg(cx, sp, tts) {
+    ExpandResult::Ready(match parse_cfg(cx, sp, tts) {
         Ok(cfg) => {
             let matches_cfg = attr::cfg_matches(
                 &cfg,
@@ -29,13 +29,13 @@ pub fn expand_cfg(
             MacEager::expr(cx.expr_bool(sp, matches_cfg))
         }
         Err(err) => {
-            err.emit();
-            DummyResult::any(sp)
+            let guar = err.emit();
+            DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
-fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
+fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, ast::MetaItem> {
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index ceb5f861078..98c0ca3a526 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -10,7 +10,7 @@ use rustc_span::Span;
 
 pub(crate) struct Expander;
 
-fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
+fn validate_input<'a>(ecx: &ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'a ast::Path> {
     use errors::CfgAccessibleInvalid::*;
     match mi.meta_item_list() {
         None => {}
@@ -46,7 +46,7 @@ impl MultiItemModifier for Expander {
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
         let template = AttributeTemplate { list: Some("path"), ..Default::default() };
         validate_attr::check_builtin_meta_item(
-            &ecx.sess.parse_sess,
+            &ecx.sess.psess,
             meta_item,
             ast::AttrStyle::Outer,
             sym::cfg_accessible,
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index cfa94b0e780..03aff6f9633 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -1,5 +1,6 @@
 use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
 
+use core::ops::ControlFlow;
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::ptr::P;
@@ -17,6 +18,7 @@ use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
+use tracing::instrument;
 
 pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
@@ -87,41 +89,40 @@ fn flat_map_annotatable(
     }
 }
 
-struct CfgFinder {
-    has_cfg_or_cfg_attr: bool,
-}
+fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
+    struct CfgFinder;
 
-impl CfgFinder {
-    fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
-        let mut finder = CfgFinder { has_cfg_or_cfg_attr: false };
-        match annotatable {
-            Annotatable::Item(item) => finder.visit_item(item),
-            Annotatable::TraitItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Trait),
-            Annotatable::ImplItem(item) => finder.visit_assoc_item(item, visit::AssocCtxt::Impl),
-            Annotatable::ForeignItem(item) => finder.visit_foreign_item(item),
-            Annotatable::Stmt(stmt) => finder.visit_stmt(stmt),
-            Annotatable::Expr(expr) => finder.visit_expr(expr),
-            Annotatable::Arm(arm) => finder.visit_arm(arm),
-            Annotatable::ExprField(field) => finder.visit_expr_field(field),
-            Annotatable::PatField(field) => finder.visit_pat_field(field),
-            Annotatable::GenericParam(param) => finder.visit_generic_param(param),
-            Annotatable::Param(param) => finder.visit_param(param),
-            Annotatable::FieldDef(field) => finder.visit_field_def(field),
-            Annotatable::Variant(variant) => finder.visit_variant(variant),
-            Annotatable::Crate(krate) => finder.visit_crate(krate),
-        };
-        finder.has_cfg_or_cfg_attr
-    }
-}
-
-impl<'ast> visit::Visitor<'ast> for CfgFinder {
-    fn visit_attribute(&mut self, attr: &'ast Attribute) {
-        // We want short-circuiting behavior, so don't use the '|=' operator.
-        self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
-            || attr
+    impl<'ast> visit::Visitor<'ast> for CfgFinder {
+        type Result = ControlFlow<()>;
+        fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
+            if attr
                 .ident()
-                .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
+                .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
+            {
+                ControlFlow::Break(())
+            } else {
+                ControlFlow::Continue(())
+            }
+        }
     }
+
+    let res = match annotatable {
+        Annotatable::Item(item) => CfgFinder.visit_item(item),
+        Annotatable::TraitItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Trait),
+        Annotatable::ImplItem(item) => CfgFinder.visit_assoc_item(item, visit::AssocCtxt::Impl),
+        Annotatable::ForeignItem(item) => CfgFinder.visit_foreign_item(item),
+        Annotatable::Stmt(stmt) => CfgFinder.visit_stmt(stmt),
+        Annotatable::Expr(expr) => CfgFinder.visit_expr(expr),
+        Annotatable::Arm(arm) => CfgFinder.visit_arm(arm),
+        Annotatable::ExprField(field) => CfgFinder.visit_expr_field(field),
+        Annotatable::PatField(field) => CfgFinder.visit_pat_field(field),
+        Annotatable::GenericParam(param) => CfgFinder.visit_generic_param(param),
+        Annotatable::Param(param) => CfgFinder.visit_param(param),
+        Annotatable::FieldDef(field) => CfgFinder.visit_field_def(field),
+        Annotatable::Variant(variant) => CfgFinder.visit_variant(variant),
+        Annotatable::Crate(krate) => CfgFinder.visit_crate(krate),
+    };
+    res.is_break()
 }
 
 impl CfgEval<'_, '_> {
@@ -132,7 +133,7 @@ impl CfgEval<'_, '_> {
     fn configure_annotatable(&mut self, mut annotatable: Annotatable) -> Option<Annotatable> {
         // Tokenizing and re-parsing the `Annotatable` can have a significant
         // performance impact, so try to avoid it if possible
-        if !CfgFinder::has_cfg_or_cfg_attr(&annotatable) {
+        if !has_cfg_or_cfg_attr(&annotatable) {
             return Some(annotatable);
         }
 
@@ -195,8 +196,7 @@ impl CfgEval<'_, '_> {
         // Re-parse the tokens, setting the `capture_cfg` flag to save extra information
         // to the captured `AttrTokenStream` (specifically, we capture
         // `AttrTokenTree::AttributesData` for all occurrences of `#[cfg]` and `#[cfg_attr]`)
-        let mut parser =
-            rustc_parse::stream_to_parser(&self.cfg.sess.parse_sess, orig_tokens, None);
+        let mut parser = Parser::new(&self.cfg.sess.psess, orig_tokens, None);
         parser.capture_cfg = true;
         match parse_annotatable_with(&mut parser) {
             Ok(a) => annotatable = a,
@@ -247,18 +247,18 @@ impl MutVisitor for CfgEval<'_, '_> {
     }
 
     fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
+        mut_visit::noop_flat_map_item(configure!(self, item), self)
     }
 
     fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        mut_visit::noop_flat_map_assoc_item(configure!(self, item), self)
+        mut_visit::noop_flat_map_item(configure!(self, item), self)
     }
 
     fn flat_map_foreign_item(
         &mut self,
         foreign_item: P<ast::ForeignItem>,
     ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
-        mut_visit::noop_flat_map_foreign_item(configure!(self, foreign_item), self)
+        mut_visit::noop_flat_map_item(configure!(self, foreign_item), self)
     }
 
     fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index d956c096d24..e9b63b4abeb 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -4,16 +4,17 @@ use crate::errors;
 use rustc_ast::attr::mk_attr;
 use rustc_ast::token;
 use rustc_ast::{self as ast, AttrItem, AttrStyle};
+use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
 use rustc_session::parse::ParseSess;
 use rustc_span::FileName;
 
-pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String]) {
+pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
     for raw_attr in attrs {
-        let mut parser = rustc_parse::new_parser_from_source_str(
-            parse_sess,
+        let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
+            psess,
             FileName::cli_crate_attr_source_code(raw_attr),
             raw_attr.clone(),
-        );
+        ));
 
         let start_span = parser.token.span;
         let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item(false) {
@@ -25,12 +26,12 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String])
         };
         let end_span = parser.token.span;
         if parser.token != token::Eof {
-            parse_sess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
+            psess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
             continue;
         }
 
         krate.attrs.push(mk_attr(
-            &parse_sess.attr_id_generator,
+            &psess.attr_id_generator,
             AttrStyle::Inner,
             path,
             args,
diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs
index f157575da79..a08e8b2819b 100644
--- a/compiler/rustc_builtin_macros/src/compile_error.rs
+++ b/compiler/rustc_builtin_macros/src/compile_error.rs
@@ -1,24 +1,26 @@
 // The compiler code necessary to support the compile_error! extension.
 
+use crate::util::get_single_str_from_tts;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_expand::base::{self, *};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::Span;
 
-pub fn expand_compile_error<'cx>(
+pub(crate) fn expand_compile_error<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    let Some(var) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
-        return DummyResult::any(sp);
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
+        Ok(var) => var,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
-    #[expect(
-        rustc::diagnostic_outside_of_impl,
-        reason = "diagnostic message is specified by user"
-    )]
+    #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
     #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
-    cx.dcx().span_err(sp, var.to_string());
+    let guar = cx.dcx().span_err(sp, var.to_string());
 
-    DummyResult::any(sp)
+    ExpandResult::Ready(DummyResult::any(sp, guar))
 }
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index dade29593af..15af79ef67d 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -1,85 +1,85 @@
-use rustc_ast as ast;
+use crate::errors;
+use crate::util::get_exprs_from_tts;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_expand::base::{self, DummyResult};
+use rustc_ast::{ExprKind, LitKind, UnOp};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_session::errors::report_lit_error;
 use rustc_span::symbol::Symbol;
 
-use crate::errors;
-
-pub fn expand_concat(
-    cx: &mut base::ExtCtxt<'_>,
+pub(crate) fn expand_concat(
+    cx: &mut ExtCtxt<'_>,
     sp: rustc_span::Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
-    let Some(es) = base::get_exprs_from_tts(cx, tts) else {
-        return DummyResult::any(sp);
+) -> MacroExpanderResult<'static> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let es = match mac {
+        Ok(es) => es,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let mut accumulator = String::new();
     let mut missing_literal = vec![];
-    let mut has_errors = false;
+    let mut guar = None;
     for e in es {
         match e.kind {
-            ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
-                Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => {
+            ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) {
+                Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => {
                     accumulator.push_str(s.as_str());
                 }
-                Ok(ast::LitKind::Char(c)) => {
+                Ok(LitKind::Char(c)) => {
                     accumulator.push(c);
                 }
-                Ok(ast::LitKind::Int(i, _)) => {
+                Ok(LitKind::Int(i, _)) => {
                     accumulator.push_str(&i.to_string());
                 }
-                Ok(ast::LitKind::Bool(b)) => {
+                Ok(LitKind::Bool(b)) => {
                     accumulator.push_str(&b.to_string());
                 }
-                Ok(ast::LitKind::CStr(..)) => {
-                    cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span });
-                    has_errors = true;
+                Ok(LitKind::CStr(..)) => {
+                    guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span }));
                 }
-                Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
-                    cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
-                    has_errors = true;
+                Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => {
+                    guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }));
                 }
-                Ok(ast::LitKind::Err) => {
-                    has_errors = true;
+                Ok(LitKind::Err(guarantee)) => {
+                    guar = Some(guarantee);
                 }
                 Err(err) => {
-                    report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
-                    has_errors = true;
+                    guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span));
                 }
             },
             // We also want to allow negative numeric literals.
-            ast::ExprKind::Unary(ast::UnOp::Neg, ref expr)
-                if let ast::ExprKind::Lit(token_lit) = expr.kind =>
-            {
-                match ast::LitKind::from_token_lit(token_lit) {
-                    Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
-                    Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
+            ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => {
+                match LitKind::from_token_lit(token_lit) {
+                    Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")),
+                    Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")),
                     Err(err) => {
-                        report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span);
-                        has_errors = true;
+                        guar = Some(report_lit_error(&cx.sess.psess, err, token_lit, e.span));
                     }
                     _ => missing_literal.push(e.span),
                 }
             }
-            ast::ExprKind::IncludedBytes(..) => {
+            ExprKind::IncludedBytes(..) => {
                 cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
             }
-            ast::ExprKind::Err => {
-                has_errors = true;
+            ExprKind::Err(guarantee) => {
+                guar = Some(guarantee);
             }
+            ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"),
             _ => {
                 missing_literal.push(e.span);
             }
         }
     }
 
-    if !missing_literal.is_empty() {
-        cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
-        return DummyResult::any(sp);
-    } else if has_errors {
-        return DummyResult::any(sp);
-    }
-    let sp = cx.with_def_site_ctxt(sp);
-    base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
+    ExpandResult::Ready(if !missing_literal.is_empty() {
+        let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
+        DummyResult::any(sp, guar)
+    } else if let Some(guar) = guar {
+        DummyResult::any(sp, guar)
+    } else {
+        let sp = cx.with_def_site_ctxt(sp);
+        MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator)))
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index a01bbeac824..3130870df41 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -1,192 +1,185 @@
-use rustc_ast as ast;
-use rustc_ast::{ptr::P, tokenstream::TokenStream};
-use rustc_expand::base::{self, DummyResult};
-use rustc_session::errors::report_lit_error;
-use rustc_span::Span;
-
 use crate::errors;
+use crate::util::get_exprs_from_tts;
+use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
+use rustc_session::errors::report_lit_error;
+use rustc_span::{ErrorGuaranteed, Span};
 
 /// Emits errors for literal expressions that are invalid inside and outside of an array.
 fn invalid_type_err(
-    cx: &mut base::ExtCtxt<'_>,
-    token_lit: ast::token::Lit,
+    cx: &ExtCtxt<'_>,
+    token_lit: token::Lit,
     span: Span,
     is_nested: bool,
-) {
+) -> ErrorGuaranteed {
     use errors::{
         ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
     };
     let snippet = cx.sess.source_map().span_to_snippet(span).ok();
     let dcx = cx.dcx();
-    match ast::LitKind::from_token_lit(token_lit) {
-        Ok(ast::LitKind::CStr(_, _)) => {
+    match LitKind::from_token_lit(token_lit) {
+        Ok(LitKind::CStr(_, _)) => {
             // Avoid ambiguity in handling of terminal `NUL` by refusing to
             // concatenate C string literals as bytes.
-            dcx.emit_err(errors::ConcatCStrLit { span: span });
+            dcx.emit_err(errors::ConcatCStrLit { span })
         }
-        Ok(ast::LitKind::Char(_)) => {
+        Ok(LitKind::Char(_)) => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
-            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg })
         }
-        Ok(ast::LitKind::Str(_, _)) => {
+        Ok(LitKind::Str(_, _)) => {
             // suggestion would be invalid if we are nested
             let sugg = if !is_nested {
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet })
             } else {
                 None
             };
-            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg })
         }
-        Ok(ast::LitKind::Float(_, _)) => {
-            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
+        Ok(LitKind::Float(_, _)) => {
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None })
         }
-        Ok(ast::LitKind::Bool(_)) => {
-            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
+        Ok(LitKind::Bool(_)) => {
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None })
         }
-        Ok(ast::LitKind::Err) => {}
-        Ok(ast::LitKind::Int(_, _)) if !is_nested => {
+        Ok(LitKind::Int(_, _)) if !is_nested => {
             let sugg =
-                snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
-            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
+                snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg })
         }
-        Ok(ast::LitKind::Int(
-            val,
-            ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
-        )) => {
+        Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => {
             assert!(val.get() > u8::MAX.into()); // must be an error
-            dcx.emit_err(ConcatBytesOob { span });
-        }
-        Ok(ast::LitKind::Int(_, _)) => {
-            dcx.emit_err(ConcatBytesNonU8 { span });
-        }
-        Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
-        Err(err) => {
-            report_lit_error(&cx.sess.parse_sess, err, token_lit, span);
+            dcx.emit_err(ConcatBytesOob { span })
         }
+        Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }),
+        Ok(LitKind::ByteStr(..) | LitKind::Byte(_)) => unreachable!(),
+        Ok(LitKind::Err(guar)) => guar,
+        Err(err) => report_lit_error(&cx.sess.psess, err, token_lit, span),
     }
 }
 
+/// Returns `expr` as a *single* byte literal if applicable.
+///
+/// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or
+/// updates `guar` accordingly.
 fn handle_array_element(
-    cx: &mut base::ExtCtxt<'_>,
-    has_errors: &mut bool,
+    cx: &ExtCtxt<'_>,
+    guar: &mut Option<ErrorGuaranteed>,
     missing_literals: &mut Vec<rustc_span::Span>,
     expr: &P<rustc_ast::Expr>,
 ) -> Option<u8> {
     let dcx = cx.dcx();
-    match expr.kind {
-        ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
-            if !*has_errors {
-                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
-            }
-            *has_errors = true;
-            None
-        }
-        ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
-            Ok(ast::LitKind::Int(
-                val,
-                ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
-            )) if val.get() <= u8::MAX.into() => Some(val.get() as u8),
 
-            Ok(ast::LitKind::Byte(val)) => Some(val),
-            Ok(ast::LitKind::ByteStr(..)) => {
-                if !*has_errors {
-                    dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
+    match expr.kind {
+        ExprKind::Lit(token_lit) => {
+            match LitKind::from_token_lit(token_lit) {
+                Ok(LitKind::Int(
+                    val,
+                    LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8),
+                )) if let Ok(val) = u8::try_from(val.get()) => {
+                    return Some(val);
                 }
-                *has_errors = true;
-                None
-            }
-            _ => {
-                if !*has_errors {
-                    invalid_type_err(cx, token_lit, expr.span, true);
+                Ok(LitKind::Byte(val)) => return Some(val),
+                Ok(LitKind::ByteStr(..)) => {
+                    guar.get_or_insert_with(|| {
+                        dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true })
+                    });
                 }
-                *has_errors = true;
-                None
-            }
-        },
-        ast::ExprKind::IncludedBytes(..) => {
-            if !*has_errors {
-                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
-            }
-            *has_errors = true;
-            None
+                _ => {
+                    guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, expr.span, true));
+                }
+            };
         }
-        _ => {
-            missing_literals.push(expr.span);
-            None
+        ExprKind::Array(_) | ExprKind::Repeat(_, _) => {
+            guar.get_or_insert_with(|| {
+                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false })
+            });
         }
+        ExprKind::IncludedBytes(..) => {
+            guar.get_or_insert_with(|| {
+                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false })
+            });
+        }
+        _ => missing_literals.push(expr.span),
     }
+
+    None
 }
 
-pub fn expand_concat_bytes(
-    cx: &mut base::ExtCtxt<'_>,
-    sp: rustc_span::Span,
+pub(crate) fn expand_concat_bytes(
+    cx: &mut ExtCtxt<'_>,
+    sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
-    let Some(es) = base::get_exprs_from_tts(cx, tts) else {
-        return DummyResult::any(sp);
+) -> MacroExpanderResult<'static> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let es = match mac {
+        Ok(es) => es,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     let mut accumulator = Vec::new();
     let mut missing_literals = vec![];
-    let mut has_errors = false;
+    let mut guar = None;
     for e in es {
         match &e.kind {
-            ast::ExprKind::Array(exprs) => {
+            ExprKind::Array(exprs) => {
                 for expr in exprs {
                     if let Some(elem) =
-                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                        handle_array_element(cx, &mut guar, &mut missing_literals, expr)
                     {
                         accumulator.push(elem);
                     }
                 }
             }
-            ast::ExprKind::Repeat(expr, count) => {
-                if let ast::ExprKind::Lit(token_lit) = count.value.kind
-                    && let Ok(ast::LitKind::Int(count_val, _)) =
-                        ast::LitKind::from_token_lit(token_lit)
+            ExprKind::Repeat(expr, count) => {
+                if let ExprKind::Lit(token_lit) = count.value.kind
+                    && let Ok(LitKind::Int(count_val, _)) = LitKind::from_token_lit(token_lit)
                 {
                     if let Some(elem) =
-                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                        handle_array_element(cx, &mut guar, &mut missing_literals, expr)
                     {
                         for _ in 0..count_val.get() {
                             accumulator.push(elem);
                         }
                     }
                 } else {
-                    cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
+                    guar = Some(
+                        cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }),
+                    );
                 }
             }
-            &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
-                Ok(ast::LitKind::Byte(val)) => {
+            &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) {
+                Ok(LitKind::Byte(val)) => {
                     accumulator.push(val);
                 }
-                Ok(ast::LitKind::ByteStr(ref bytes, _)) => {
+                Ok(LitKind::ByteStr(ref bytes, _)) => {
                     accumulator.extend_from_slice(bytes);
                 }
                 _ => {
-                    if !has_errors {
-                        invalid_type_err(cx, token_lit, e.span, false);
-                    }
-                    has_errors = true;
+                    guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false));
                 }
             },
-            ast::ExprKind::IncludedBytes(bytes) => {
+            ExprKind::IncludedBytes(bytes) => {
                 accumulator.extend_from_slice(bytes);
             }
-            ast::ExprKind::Err => {
-                has_errors = true;
+            ExprKind::Err(guarantee) => {
+                guar = Some(*guarantee);
             }
+            ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"),
             _ => {
                 missing_literals.push(e.span);
             }
         }
     }
-    if !missing_literals.is_empty() {
-        cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
-        return base::MacEager::expr(DummyResult::raw_expr(sp, true));
-    } else if has_errors {
-        return base::MacEager::expr(DummyResult::raw_expr(sp, true));
-    }
-    let sp = cx.with_def_site_ctxt(sp);
-    base::MacEager::expr(cx.expr_byte_str(sp, accumulator))
+    ExpandResult::Ready(if !missing_literals.is_empty() {
+        let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
+        MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
+    } else if let Some(guar) = guar {
+        MacEager::expr(DummyResult::raw_expr(sp, Some(guar)))
+    } else {
+        let sp = cx.with_def_site_ctxt(sp);
+        MacEager::expr(cx.expr_byte_str(sp, accumulator))
+    })
 }
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index 17fd3901cc6..13729a9d250 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -1,21 +1,21 @@
-use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_expand::base::{self, *};
+use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::Span;
 
 use crate::errors;
 
-pub fn expand_concat_idents<'cx>(
+pub(crate) fn expand_concat_idents<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     if tts.is_empty() {
-        cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
-        return DummyResult::any(sp);
+        let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
+        return ExpandResult::Ready(DummyResult::any(sp, guar));
     }
 
     let mut res_str = String::new();
@@ -24,8 +24,8 @@ pub fn expand_concat_idents<'cx>(
             match e {
                 TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
                 _ => {
-                    cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
-                    return DummyResult::any(sp);
+                    let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
+                    return ExpandResult::Ready(DummyResult::any(sp, guar));
                 }
             }
         } else {
@@ -36,8 +36,8 @@ pub fn expand_concat_idents<'cx>(
                 }
             }
 
-            cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
-            return DummyResult::any(sp);
+            let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     }
 
@@ -47,26 +47,26 @@ pub fn expand_concat_idents<'cx>(
         ident: Ident,
     }
 
-    impl base::MacResult for ConcatIdentsResult {
-        fn make_expr(self: Box<Self>) -> Option<P<ast::Expr>> {
-            Some(P(ast::Expr {
-                id: ast::DUMMY_NODE_ID,
-                kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)),
+    impl MacResult for ConcatIdentsResult {
+        fn make_expr(self: Box<Self>) -> Option<P<Expr>> {
+            Some(P(Expr {
+                id: DUMMY_NODE_ID,
+                kind: ExprKind::Path(None, Path::from_ident(self.ident)),
                 span: self.ident.span,
-                attrs: ast::AttrVec::new(),
+                attrs: AttrVec::new(),
                 tokens: None,
             }))
         }
 
-        fn make_ty(self: Box<Self>) -> Option<P<ast::Ty>> {
-            Some(P(ast::Ty {
-                id: ast::DUMMY_NODE_ID,
-                kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)),
+        fn make_ty(self: Box<Self>) -> Option<P<Ty>> {
+            Some(P(Ty {
+                id: DUMMY_NODE_ID,
+                kind: TyKind::Path(None, Path::from_ident(self.ident)),
                 span: self.ident.span,
                 tokens: None,
             }))
         }
     }
 
-    Box::new(ConcatIdentsResult { ident })
+    ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
 }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 7388e133c53..d14858e5c1d 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -3,14 +3,18 @@ use crate::errors;
 
 use rustc_ast as ast;
 use rustc_ast::{GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
-use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
+use rustc_expand::base::{
+    Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier,
+};
 use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{ErrorGuaranteed, Span};
 
-pub(crate) struct Expander(pub bool);
+pub(crate) struct Expander {
+    pub is_const: bool,
+}
 
 impl MultiItemModifier for Expander {
     fn expand(
@@ -34,7 +38,7 @@ impl MultiItemModifier for Expander {
                 let template =
                     AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
                 validate_attr::check_builtin_meta_item(
-                    &sess.parse_sess,
+                    &sess.psess,
                     meta_item,
                     ast::AttrStyle::Outer,
                     sym::derive,
@@ -58,7 +62,12 @@ impl MultiItemModifier for Expander {
                                 report_path_args(sess, meta);
                                 meta.path.clone()
                             })
-                            .map(|path| (path, dummy_annotatable(), None, self.0))
+                            .map(|path| DeriveResolution {
+                                path,
+                                item: dummy_annotatable(),
+                                exts: None,
+                                is_const: self.is_const,
+                            })
                             .collect()
                     }
                     _ => vec![],
@@ -67,15 +76,15 @@ impl MultiItemModifier for Expander {
                 // Do not configure or clone items unless necessary.
                 match &mut resolutions[..] {
                     [] => {}
-                    [(_, first_item, ..), others @ ..] => {
-                        *first_item = cfg_eval(
+                    [first, others @ ..] => {
+                        first.item = cfg_eval(
                             sess,
                             features,
                             item.clone(),
                             ecx.current_expansion.lint_node_id,
                         );
-                        for (_, item, _, _) in others {
-                            *item = first_item.clone();
+                        for other in others {
+                            other.item = first.item.clone();
                         }
                     }
                 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 8027ca2e7bb..97e2344ff30 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -5,8 +5,8 @@ use rustc_ast::MetaItem;
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::Span;
 
-pub fn expand_deriving_copy(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_copy(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -28,8 +28,8 @@ pub fn expand_deriving_copy(
     trait_def.expand(cx, mitem, item, push);
 }
 
-pub fn expand_deriving_const_param_ty(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_const_param_ty(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 7bf19f61166..abcb402a46f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -8,8 +8,8 @@ use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_clone(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_clone(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -94,7 +94,7 @@ pub fn expand_deriving_clone(
 
 fn cs_clone_simple(
     name: &str,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     is_union: bool,
@@ -110,7 +110,9 @@ fn cs_clone_simple(
                 && !seen_type_names.insert(name)
             {
                 // Already produced an assertion for this type.
-            } else {
+                // Anonymous structs or unions must be eliminated as they cannot be
+                // type parameters.
+            } else if !field.ty.kind.is_anon_adt() {
                 // let _: AssertParamIsClone<FieldTy>;
                 super::assert_ty_bounds(
                     cx,
@@ -155,14 +157,14 @@ fn cs_clone_simple(
 
 fn cs_clone(
     name: &str,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
     let ctor_path;
     let all_fields;
     let fn_path = cx.std_path(&[sym::clone, sym::Clone, sym::clone]);
-    let subcall = |cx: &mut ExtCtxt<'_>, field: &FieldInfo| {
+    let subcall = |cx: &ExtCtxt<'_>, field: &FieldInfo| {
         let args = thin_vec![field.self_expr.clone()];
         cx.expr_call_global(field.span, fn_path.clone(), args)
     };
@@ -179,8 +181,8 @@ fn cs_clone(
             all_fields = af;
             vdata = &variant.data;
         }
-        EnumTag(..) | AllFieldlessEnum(..) => {
-            cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
+        EnumDiscr(..) | AllFieldlessEnum(..) => {
+            cx.dcx().span_bug(trait_span, format!("enum discriminants in `derive({name})`",))
         }
         StaticEnum(..) | StaticStruct(..) => {
             cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index ce3fa1ab32c..53a15131605 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -9,8 +9,8 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_eq(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_eq(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -49,7 +49,7 @@ pub fn expand_deriving_eq(
 }
 
 fn cs_total_eq_assert(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index 0923acfeedd..8470d466a23 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -7,8 +7,8 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
-pub fn expand_deriving_ord(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_ord(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -39,7 +39,7 @@ pub fn expand_deriving_ord(
     trait_def.expand(cx, mitem, item, push)
 }
 
-pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+pub(crate) fn cs_cmp(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
     let cmp_path = cx.std_path(&[sym::cmp, sym::Ord, sym::cmp]);
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 006110cd4b1..a6457f4a433 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -8,15 +8,15 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
-pub fn expand_deriving_partial_eq(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_partial_eq(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
     push: &mut dyn FnMut(Annotatable),
     is_const: bool,
 ) {
-    fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+    fn cs_eq(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
         let base = true;
         let expr = cs_fold(
             true, // use foldl
@@ -31,7 +31,7 @@ pub fn expand_deriving_partial_eq(
                     };
 
                     // We received arguments of type `&T`. Convert them to type `T` by stripping
-                    // any leading `&` or adding `*`. This isn't necessary for type checking, but
+                    // any leading `&`. This isn't necessary for type checking, but
                     // it results in better error messages if something goes wrong.
                     //
                     // Note: for arguments that look like `&{ x }`, which occur with packed
@@ -53,8 +53,7 @@ pub fn expand_deriving_partial_eq(
                                 inner.clone()
                             }
                         } else {
-                            // No leading `&`: add a leading `*`.
-                            cx.expr_deref(field.span, expr.clone())
+                            expr.clone()
                         }
                     };
                     cx.expr_binary(
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 6eccd67f8af..006e5a3d268 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -7,8 +7,8 @@ use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
-pub fn expand_deriving_partial_ord(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_partial_ord(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -20,12 +20,12 @@ pub fn expand_deriving_partial_ord(
         Path(Path::new_(pathvec_std!(option::Option), vec![Box::new(ordering_ty)], PathKind::Std));
 
     // Order in which to perform matching
-    let tag_then_data = if let Annotatable::Item(item) = item
+    let discr_then_data = if let Annotatable::Item(item) = item
         && let ItemKind::Enum(def, _) = &item.kind
     {
         let dataful: Vec<bool> = def.variants.iter().map(|v| !v.data.fields().is_empty()).collect();
         match dataful.iter().filter(|&&b| b).count() {
-            // No data, placing the tag check first makes codegen simpler
+            // No data, placing the discriminant check first makes codegen simpler
             0 => true,
             1..=2 => false,
             _ => (0..dataful.len() - 1).any(|i| {
@@ -50,7 +50,7 @@ pub fn expand_deriving_partial_ord(
         attributes: thin_vec![cx.attr_word(sym::inline, span)],
         fieldless_variants_strategy: FieldlessVariantsStrategy::Unify,
         combine_substructure: combine_substructure(Box::new(|cx, span, substr| {
-            cs_partial_cmp(cx, span, substr, tag_then_data)
+            cs_partial_cmp(cx, span, substr, discr_then_data)
         })),
     };
 
@@ -69,10 +69,10 @@ pub fn expand_deriving_partial_ord(
 }
 
 fn cs_partial_cmp(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     substr: &Substructure<'_>,
-    tag_then_data: bool,
+    discr_then_data: bool,
 ) -> BlockOrExpr {
     let test_id = Ident::new(sym::cmp, span);
     let equal_path = cx.path_global(span, cx.std_path(&[sym::cmp, sym::Ordering, sym::Equal]));
@@ -108,12 +108,12 @@ fn cs_partial_cmp(
                 //     cmp => cmp
                 // }
                 // ```
-                // where `expr2` is `partial_cmp(self_tag, other_tag)`, and `expr1` is a `match`
-                //  against the enum variants. This means that we begin by comparing the enum tags,
+                // where `expr2` is `partial_cmp(self_discr, other_discr)`, and `expr1` is a `match`
+                // against the enum variants. This means that we begin by comparing the enum discriminants,
                 // before either inspecting their contents (if they match), or returning
-                // the `cmp::Ordering` of comparing the enum tags.
+                // the `cmp::Ordering` of comparing the enum discriminants.
                 // ```
-                // match partial_cmp(self_tag, other_tag) {
+                // match partial_cmp(self_discr, other_discr) {
                 //     Some(Ordering::Equal) => match (self, other)  {
                 //         (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
                 //         (Self::B(self_0), Self::B(other_0)) => partial_cmp(self_0, other_0),
@@ -126,13 +126,13 @@ fn cs_partial_cmp(
                 // ```
                 // match (self, other) {
                 //     (Self::A(self_0), Self::A(other_0)) => partial_cmp(self_0, other_0),
-                //     _ => partial_cmp(self_tag, other_tag)
+                //     _ => partial_cmp(self_discr, other_discr)
                 // }
                 // ```
                 // Reference: https://github.com/rust-lang/rust/pull/103659#issuecomment-1328126354
 
-                if !tag_then_data
-                    && let ExprKind::Match(_, arms) = &mut expr1.kind
+                if !discr_then_data
+                    && let ExprKind::Match(_, arms, _) = &mut expr1.kind
                     && let Some(last) = arms.last_mut()
                     && let PatKind::Wild = last.pat.kind
                 {
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index b11a1b6cda1..57ec0435e3e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -2,15 +2,14 @@ use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::deriving::path_std;
 
-use ast::EnumDef;
-use rustc_ast::{self as ast, MetaItem};
+use rustc_ast::{self as ast, EnumDef, MetaItem};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_debug(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_debug(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -46,15 +45,15 @@ pub fn expand_deriving_debug(
     trait_def.expand(cx, mitem, item, push)
 }
 
-fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
+fn show_substructure(cx: &ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     // We want to make sure we have the ctxt set so that we can use unstable methods
     let span = cx.with_def_site_ctxt(span);
 
     let (ident, vdata, fields) = match substr.fields {
         Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
-        EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
+        EnumMatching(_, v, fields) => (v.ident, &v.data, fields),
         AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
-        EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
+        EnumDiscr(..) | StaticStruct(..) | StaticEnum(..) => {
             cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
         }
     };
@@ -210,7 +209,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
 /// }
 /// ```
 fn show_fieldless_enum(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     span: Span,
     def: &EnumDef,
     substr: &Substructure<'_>,
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 97d6b82de98..e9851c87aea 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -10,8 +10,8 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_rustc_decodable(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_rustc_decodable(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -63,7 +63,7 @@ pub fn expand_deriving_rustc_decodable(
 }
 
 fn decodable_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
@@ -186,19 +186,19 @@ fn decodable_substructure(
 /// - `outer_pat_path` is the path to this enum variant/struct
 /// - `getarg` should retrieve the `usize`-th field with name `@str`.
 fn decode_static_fields<F>(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     outer_pat_path: ast::Path,
     fields: &StaticFields,
     mut getarg: F,
 ) -> P<Expr>
 where
-    F: FnMut(&mut ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
+    F: FnMut(&ExtCtxt<'_>, Span, Symbol, usize) -> P<Expr>,
 {
     match fields {
         Unnamed(fields, is_tuple) => {
             let path_expr = cx.expr_path(outer_pat_path);
-            if !*is_tuple {
+            if matches!(is_tuple, IsTuple::No) {
                 path_expr
             } else {
                 let fields = fields
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index d5a42566e19..577523a1d5a 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -1,17 +1,19 @@
 use crate::deriving::generic::ty::*;
 use crate::deriving::generic::*;
 use crate::errors;
+use core::ops::ControlFlow;
 use rustc_ast as ast;
-use rustc_ast::{attr, walk_list, EnumDef, VariantData};
+use rustc_ast::visit::visit_opt;
+use rustc_ast::{attr, EnumDef, VariantData};
 use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 use smallvec::SmallVec;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_default(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_default(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &ast::MetaItem,
     item: &Annotatable,
@@ -52,7 +54,7 @@ pub fn expand_deriving_default(
 }
 
 fn default_struct_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     summary: &StaticFields,
@@ -62,8 +64,8 @@ fn default_struct_substructure(
     let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new());
 
     let expr = match summary {
-        Unnamed(_, false) => cx.expr_ident(trait_span, substr.type_ident),
-        Unnamed(fields, true) => {
+        Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident),
+        Unnamed(fields, IsTuple::Yes) => {
             let exprs = fields.iter().map(|sp| default_call(*sp)).collect();
             cx.expr_call_ident(trait_span, substr.type_ident, exprs)
         }
@@ -79,29 +81,32 @@ fn default_struct_substructure(
 }
 
 fn default_enum_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     enum_def: &EnumDef,
 ) -> BlockOrExpr {
-    let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span)
-        && let Ok(_) = validate_default_attribute(cx, default_variant)
-    {
-        // We now know there is exactly one unit variant with exactly one `#[default]` attribute.
-        cx.expr_path(cx.path(
-            default_variant.span,
-            vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
-        ))
-    } else {
-        DummyResult::raw_expr(trait_span, true)
+    let expr = match try {
+        let default_variant = extract_default_variant(cx, enum_def, trait_span)?;
+        validate_default_attribute(cx, default_variant)?;
+        default_variant
+    } {
+        Ok(default_variant) => {
+            // We now know there is exactly one unit variant with exactly one `#[default]` attribute.
+            cx.expr_path(cx.path(
+                default_variant.span,
+                vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident],
+            ))
+        }
+        Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)),
     };
     BlockOrExpr::new_expr(expr)
 }
 
 fn extract_default_variant<'a>(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     enum_def: &'a EnumDef,
     trait_span: Span,
-) -> Result<&'a rustc_ast::Variant, ()> {
+) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> {
     let default_variants: SmallVec<[_; 1]> = enum_def
         .variants
         .iter()
@@ -120,9 +125,9 @@ fn extract_default_variant<'a>(
             let suggs = possible_defaults
                 .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
                 .collect();
-            cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
+            let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
 
-            return Err(());
+            return Err(guar);
         }
         [first, rest @ ..] => {
             let suggs = default_variants
@@ -140,37 +145,37 @@ fn extract_default_variant<'a>(
                         .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
                 })
                 .collect();
-            cx.dcx().emit_err(errors::MultipleDefaults {
+            let guar = cx.dcx().emit_err(errors::MultipleDefaults {
                 span: trait_span,
                 first: first.span,
                 additional: rest.iter().map(|v| v.span).collect(),
                 suggs,
             });
-            return Err(());
+            return Err(guar);
         }
     };
 
     if !matches!(variant.data, VariantData::Unit(..)) {
-        cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
-        return Err(());
+        let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
+        return Err(guar);
     }
 
     if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
-        cx.dcx().emit_err(errors::NonExhaustiveDefault {
+        let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault {
             span: variant.ident.span,
             non_exhaustive: non_exhaustive_attr.span,
         });
 
-        return Err(());
+        return Err(guar);
     }
 
     Ok(variant)
 }
 
 fn validate_default_attribute(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     default_variant: &rustc_ast::Variant,
-) -> Result<(), ()> {
+) -> Result<(), ErrorGuaranteed> {
     let attrs: SmallVec<[_; 1]> =
         attr::filter_by_name(&default_variant.attrs, kw::Default).collect();
 
@@ -183,7 +188,7 @@ fn validate_default_attribute(
             let sugg = errors::MultipleDefaultAttrsSugg {
                 spans: rest.iter().map(|attr| attr.span).collect(),
             };
-            cx.dcx().emit_err(errors::MultipleDefaultAttrs {
+            let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs {
                 span: default_variant.ident.span,
                 first: first.span,
                 first_rest: rest[0].span,
@@ -192,13 +197,13 @@ fn validate_default_attribute(
                 sugg,
             });
 
-            return Err(());
+            return Err(guar);
         }
     };
     if !attr.is_word() {
-        cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span });
+        let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span });
 
-        return Err(());
+        return Err(guar);
     }
     Ok(())
 }
@@ -219,7 +224,7 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
         self.visit_ident(v.ident);
         self.visit_vis(&v.vis);
         self.visit_variant_data(&v.data);
-        walk_list!(self, visit_anon_const, &v.disr_expr);
+        visit_opt!(self, visit_anon_const, &v.disr_expr);
         for attr in &v.attrs {
             rustc_ast::visit::walk_attribute(self, attr);
         }
@@ -227,20 +232,19 @@ impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, '
 }
 
 fn has_a_default_variant(item: &Annotatable) -> bool {
-    struct HasDefaultAttrOnVariant {
-        found: bool,
-    }
+    struct HasDefaultAttrOnVariant;
 
     impl<'ast> rustc_ast::visit::Visitor<'ast> for HasDefaultAttrOnVariant {
-        fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) {
+        type Result = ControlFlow<()>;
+        fn visit_variant(&mut self, v: &'ast rustc_ast::Variant) -> ControlFlow<()> {
             if v.attrs.iter().any(|attr| attr.has_name(kw::Default)) {
-                self.found = true;
+                ControlFlow::Break(())
+            } else {
+                // no need to subrecurse.
+                ControlFlow::Continue(())
             }
-            // no need to subrecurse.
         }
     }
 
-    let mut visitor = HasDefaultAttrOnVariant { found: false };
-    item.visit_with(&mut visitor);
-    visitor.found
+    item.visit_with(&mut HasDefaultAttrOnVariant).is_break()
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 14d93a8cc23..3bd74d8d019 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -94,8 +94,8 @@ use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand_deriving_rustc_encodable(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_rustc_encodable(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -147,7 +147,7 @@ pub fn expand_deriving_rustc_encodable(
 }
 
 fn encodable_substructure(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substr: &Substructure<'_>,
     krate: Symbol,
@@ -226,7 +226,7 @@ fn encodable_substructure(
             BlockOrExpr::new_expr(expr)
         }
 
-        EnumMatching(idx, _, variant, fields) => {
+        EnumMatching(idx, variant, fields) => {
             // We're not generating an AST that the borrow checker is expecting,
             // so we need to generate a unique local variable to take the
             // mutable loan out on, otherwise we get conflicts which don't
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6eeb028728c..ba289f9552e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -21,7 +21,7 @@
 //!   `struct T(i32, char)`).
 //! - `EnumMatching`, when `Self` is an enum and all the arguments are the
 //!   same variant of the enum (e.g., `Some(1)`, `Some(3)` and `Some(4)`)
-//! - `EnumTag` when `Self` is an enum, for comparing the enum tags.
+//! - `EnumDiscr` when `Self` is an enum, for comparing the enum discriminants.
 //! - `StaticEnum` and `StaticStruct` for static methods, where the type
 //!   being derived upon is either an enum or struct respectively. (Any
 //!   argument with type Self is just grouped among the non-self
@@ -143,11 +143,11 @@
 //! )
 //! ```
 //!
-//! For the tags,
+//! For the discriminants,
 //!
 //! ```text
-//! EnumTag(
-//!     &[<ident of self tag>, <ident of other tag>],
+//! EnumDiscr(
+//!     &[<ident of self discriminant>, <ident of other discriminant>],
 //!     <expr to combine with>,
 //! )
 //! ```
@@ -174,13 +174,13 @@
 //! )
 //! ```
 
-pub use StaticFields::*;
-pub use SubstructureFields::*;
+pub(crate) use StaticFields::*;
+pub(crate) use SubstructureFields::*;
 
 use crate::{deriving, errors};
 use rustc_ast::ptr::P;
 use rustc_ast::{
-    self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
+    self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
     Mutability, PatKind, TyKind, VariantData,
 };
 use rustc_attr as attr;
@@ -195,9 +195,9 @@ use std::vec;
 use thin_vec::{thin_vec, ThinVec};
 use ty::{Bounds, Path, Ref, Self_, Ty};
 
-pub mod ty;
+pub(crate) mod ty;
 
-pub struct TraitDef<'a> {
+pub(crate) struct TraitDef<'a> {
     /// The span for the current #[derive(Foo)] header.
     pub span: Span,
 
@@ -224,7 +224,7 @@ pub struct TraitDef<'a> {
     pub is_const: bool,
 }
 
-pub struct MethodDef<'a> {
+pub(crate) struct MethodDef<'a> {
     /// name of the method
     pub name: Symbol,
     /// List of generics, e.g., `R: rand::Rng`
@@ -248,7 +248,7 @@ pub struct MethodDef<'a> {
 
 /// How to handle fieldless enum variants.
 #[derive(PartialEq)]
-pub enum FieldlessVariantsStrategy {
+pub(crate) enum FieldlessVariantsStrategy {
     /// Combine fieldless variants into a single match arm.
     /// This assumes that relevant information has been handled
     /// by looking at the enum's discriminant.
@@ -263,7 +263,7 @@ pub enum FieldlessVariantsStrategy {
 }
 
 /// All the data about the data structure/method being derived upon.
-pub struct Substructure<'a> {
+pub(crate) struct Substructure<'a> {
     /// ident of self
     pub type_ident: Ident,
     /// Verbatim access to any non-selflike arguments, i.e. arguments that
@@ -273,7 +273,7 @@ pub struct Substructure<'a> {
 }
 
 /// Summary of the relevant parts of a struct/enum field.
-pub struct FieldInfo {
+pub(crate) struct FieldInfo {
     pub span: Span,
     /// None for tuple structs/normal enum variants, Some for normal
     /// structs/struct enum variants.
@@ -286,16 +286,22 @@ pub struct FieldInfo {
     pub other_selflike_exprs: Vec<P<Expr>>,
 }
 
+#[derive(Copy, Clone)]
+pub(crate) enum IsTuple {
+    No,
+    Yes,
+}
+
 /// Fields for a static method
-pub enum StaticFields {
+pub(crate) enum StaticFields {
     /// Tuple and unit structs/enum variants like this.
-    Unnamed(Vec<Span>, bool /*is tuple*/),
+    Unnamed(Vec<Span>, IsTuple),
     /// Normal structs/struct variants.
     Named(Vec<(Ident, Span)>),
 }
 
 /// A summary of the possible sets of fields.
-pub enum SubstructureFields<'a> {
+pub(crate) enum SubstructureFields<'a> {
     /// A non-static method where `Self` is a struct.
     Struct(&'a ast::VariantData, Vec<FieldInfo>),
 
@@ -304,15 +310,15 @@ pub enum SubstructureFields<'a> {
     /// variants has any fields).
     AllFieldlessEnum(&'a ast::EnumDef),
 
-    /// Matching variants of the enum: variant index, variant count, ast::Variant,
+    /// Matching variants of the enum: variant index, ast::Variant,
     /// fields: the field name is only non-`None` in the case of a struct
     /// variant.
-    EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo>),
+    EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo>),
 
-    /// The tag of an enum. The first field is a `FieldInfo` for the tags, as
+    /// The discriminant of an enum. The first field is a `FieldInfo` for the discriminants, as
     /// if they were fields. The second field is the expression to combine the
-    /// tag expression with; it will be `None` if no match is necessary.
-    EnumTag(FieldInfo, Option<P<Expr>>),
+    /// discriminant expression with; it will be `None` if no match is necessary.
+    EnumDiscr(FieldInfo, Option<P<Expr>>),
 
     /// A static method where `Self` is a struct.
     StaticStruct(&'a ast::VariantData, StaticFields),
@@ -323,10 +329,10 @@ pub enum SubstructureFields<'a> {
 
 /// Combine the values of all the fields together. The last argument is
 /// all the fields of all the structures.
-pub type CombineSubstructureFunc<'a> =
-    Box<dyn FnMut(&mut ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
+pub(crate) type CombineSubstructureFunc<'a> =
+    Box<dyn FnMut(&ExtCtxt<'_>, Span, &Substructure<'_>) -> BlockOrExpr + 'a>;
 
-pub fn combine_substructure(
+pub(crate) fn combine_substructure(
     f: CombineSubstructureFunc<'_>,
 ) -> RefCell<CombineSubstructureFunc<'_>> {
     RefCell::new(f)
@@ -343,7 +349,7 @@ struct TypeParameter {
 /// avoiding the insertion of any unnecessary blocks.
 ///
 /// The statements come before the expression.
-pub struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>);
+pub(crate) struct BlockOrExpr(ThinVec<ast::Stmt>, Option<P<Expr>>);
 
 impl BlockOrExpr {
     pub fn new_stmts(stmts: ThinVec<ast::Stmt>) -> BlockOrExpr {
@@ -406,6 +412,15 @@ fn find_type_parameters(
 
     impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
         fn visit_ty(&mut self, ty: &'a ast::Ty) {
+            let stack_len = self.bound_generic_params_stack.len();
+            if let ast::TyKind::BareFn(bare_fn) = &ty.kind
+                && !bare_fn.generic_params.is_empty()
+            {
+                // Given a field `x: for<'a> fn(T::SomeType<'a>)`, we wan't to account for `'a` so
+                // that we generate `where for<'a> T::SomeType<'a>: ::core::clone::Clone`. #122622
+                self.bound_generic_params_stack.extend(bare_fn.generic_params.iter().cloned());
+            }
+
             if let ast::TyKind::Path(_, path) = &ty.kind
                 && let Some(segment) = path.segments.first()
                 && self.ty_param_names.contains(&segment.ident.name)
@@ -416,7 +431,8 @@ fn find_type_parameters(
                 });
             }
 
-            visit::walk_ty(self, ty)
+            visit::walk_ty(self, ty);
+            self.bound_generic_params_stack.truncate(stack_len);
         }
 
         // Place bound generic params on a stack, to extract them when a type is encountered.
@@ -448,7 +464,7 @@ fn find_type_parameters(
 impl<'a> TraitDef<'a> {
     pub fn expand(
         self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         mitem: &ast::MetaItem,
         item: &'a Annotatable,
         push: &mut dyn FnMut(Annotatable),
@@ -458,7 +474,7 @@ impl<'a> TraitDef<'a> {
 
     pub fn expand_ext(
         self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         mitem: &ast::MetaItem,
         item: &'a Annotatable,
         push: &mut dyn FnMut(Annotatable),
@@ -571,7 +587,7 @@ impl<'a> TraitDef<'a> {
     /// therefore does not get bound by the derived trait.
     fn create_derived_impl(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         type_ident: Ident,
         generics: &Generics,
         field_tys: Vec<P<ast::Ty>>,
@@ -595,11 +611,7 @@ impl<'a> TraitDef<'a> {
                 kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
                     defaultness: ast::Defaultness::Final,
                     generics: Generics::default(),
-                    where_clauses: (
-                        ast::TyAliasWhereClause::default(),
-                        ast::TyAliasWhereClause::default(),
-                    ),
-                    where_predicates_split: 0,
+                    where_clauses: ast::TyAliasWhereClauses::default(),
                     bounds: Vec::new(),
                     ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
                 })),
@@ -786,7 +798,7 @@ impl<'a> TraitDef<'a> {
             Ident::empty(),
             attrs,
             ast::ItemKind::Impl(Box::new(ast::Impl {
-                unsafety: ast::Unsafe::No,
+                safety: ast::Safety::Default,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
                 constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
@@ -800,7 +812,7 @@ impl<'a> TraitDef<'a> {
 
     fn expand_struct_def(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_def: &'a VariantData,
         type_ident: Ident,
         generics: &Generics,
@@ -854,7 +866,7 @@ impl<'a> TraitDef<'a> {
 
     fn expand_enum_def(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         enum_def: &'a EnumDef,
         type_ident: Ident,
         generics: &Generics,
@@ -912,7 +924,7 @@ impl<'a> TraitDef<'a> {
 impl<'a> MethodDef<'a> {
     fn call_substructure_method(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         nonselflike_args: &[P<Expr>],
@@ -927,7 +939,7 @@ impl<'a> MethodDef<'a> {
 
     fn get_ret_ty(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         generics: &Generics,
         type_ident: Ident,
@@ -948,7 +960,7 @@ impl<'a> MethodDef<'a> {
     //   `&self`.
     fn extract_arg_details(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         generics: &Generics,
@@ -984,7 +996,7 @@ impl<'a> MethodDef<'a> {
 
     fn create_method(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         type_ident: Ident,
         generics: &Generics,
@@ -1075,7 +1087,7 @@ impl<'a> MethodDef<'a> {
     /// ```
     fn expand_struct_method_body<'b>(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         struct_def: &'b VariantData,
         type_ident: Ident,
@@ -1098,7 +1110,7 @@ impl<'a> MethodDef<'a> {
 
     fn expand_static_struct_method_body(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         struct_def: &VariantData,
         type_ident: Ident,
@@ -1135,9 +1147,9 @@ impl<'a> MethodDef<'a> {
     /// impl ::core::cmp::PartialEq for A {
     ///     #[inline]
     ///     fn eq(&self, other: &A) -> bool {
-    ///         let __self_tag = ::core::intrinsics::discriminant_value(self);
-    ///         let __arg1_tag = ::core::intrinsics::discriminant_value(other);
-    ///         __self_tag == __arg1_tag
+    ///         let __self_discr = ::core::intrinsics::discriminant_value(self);
+    ///         let __arg1_discr = ::core::intrinsics::discriminant_value(other);
+    ///         __self_discr == __arg1_discr
     ///             && match (self, other) {
     ///                 (A::A2(__self_0), A::A2(__arg1_0)) => *__self_0 == *__arg1_0,
     ///                 _ => true,
@@ -1146,13 +1158,13 @@ impl<'a> MethodDef<'a> {
     /// }
     /// ```
     ///
-    /// Creates a tag check combined with a match for a tuple of all
+    /// Creates a discriminant check combined with a match for a tuple of all
     /// `selflike_args`, with an arm for each variant with fields, possibly an
     /// arm for each fieldless variant (if `unify_fieldless_variants` is not
     /// `Unify`), and possibly a default arm.
     fn expand_enum_method_body<'b>(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'b>,
         enum_def: &'b EnumDef,
         type_ident: Ident,
@@ -1167,7 +1179,7 @@ impl<'a> MethodDef<'a> {
         let span = trait_.span;
         let variants = &enum_def.variants;
 
-        // Traits that unify fieldless variants always use the tag(s).
+        // Traits that unify fieldless variants always use the discriminant(s).
         let unify_fieldless_variants =
             self.fieldless_variants_strategy == FieldlessVariantsStrategy::Unify;
 
@@ -1197,25 +1209,25 @@ impl<'a> MethodDef<'a> {
         //
         // e.g. for `PartialEq::eq` builds two statements:
         // ```
-        // let __self_tag = ::core::intrinsics::discriminant_value(self);
-        // let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        // let __self_discr = ::core::intrinsics::discriminant_value(self);
+        // let __arg1_discr = ::core::intrinsics::discriminant_value(other);
         // ```
-        let get_tag_pieces = |cx: &ExtCtxt<'_>| {
-            let tag_idents: Vec<_> = prefixes
+        let get_discr_pieces = |cx: &ExtCtxt<'_>| {
+            let discr_idents: Vec<_> = prefixes
                 .iter()
-                .map(|name| Ident::from_str_and_span(&format!("{name}_tag"), span))
+                .map(|name| Ident::from_str_and_span(&format!("{name}_discr"), span))
                 .collect();
 
-            let mut tag_exprs: Vec<_> = tag_idents
+            let mut discr_exprs: Vec<_> = discr_idents
                 .iter()
                 .map(|&ident| cx.expr_addr_of(span, cx.expr_ident(span, ident)))
                 .collect();
 
-            let self_expr = tag_exprs.remove(0);
-            let other_selflike_exprs = tag_exprs;
-            let tag_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
+            let self_expr = discr_exprs.remove(0);
+            let other_selflike_exprs = discr_exprs;
+            let discr_field = FieldInfo { span, name: None, self_expr, other_selflike_exprs };
 
-            let tag_let_stmts: ThinVec<_> = iter::zip(&tag_idents, &selflike_args)
+            let discr_let_stmts: ThinVec<_> = iter::zip(&discr_idents, &selflike_args)
                 .map(|(&ident, selflike_arg)| {
                     let variant_value = deriving::call_intrinsic(
                         cx,
@@ -1227,7 +1239,7 @@ impl<'a> MethodDef<'a> {
                 })
                 .collect();
 
-            (tag_field, tag_let_stmts)
+            (discr_field, discr_let_stmts)
         };
 
         // There are some special cases involving fieldless enums where no
@@ -1237,19 +1249,19 @@ impl<'a> MethodDef<'a> {
             if variants.len() > 1 {
                 match self.fieldless_variants_strategy {
                     FieldlessVariantsStrategy::Unify => {
-                        // If the type is fieldless and the trait uses the tag and
+                        // If the type is fieldless and the trait uses the discriminant and
                         // there are multiple variants, we need just an operation on
-                        // the tag(s).
-                        let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
-                        let mut tag_check = self.call_substructure_method(
+                        // the discriminant(s).
+                        let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
+                        let mut discr_check = self.call_substructure_method(
                             cx,
                             trait_,
                             type_ident,
                             nonselflike_args,
-                            &EnumTag(tag_field, None),
+                            &EnumDiscr(discr_field, None),
                         );
-                        tag_let_stmts.append(&mut tag_check.0);
-                        return BlockOrExpr(tag_let_stmts, tag_check.1);
+                        discr_let_stmts.append(&mut discr_check.0);
+                        return BlockOrExpr(discr_let_stmts, discr_check.1);
                     }
                     FieldlessVariantsStrategy::SpecializeIfAllVariantsFieldless => {
                         return self.call_substructure_method(
@@ -1264,13 +1276,13 @@ impl<'a> MethodDef<'a> {
                 }
             } else if variants.len() == 1 {
                 // If there is a single variant, we don't need an operation on
-                // the tag(s). Just use the most degenerate result.
+                // the discriminant(s). Just use the most degenerate result.
                 return self.call_substructure_method(
                     cx,
                     trait_,
                     type_ident,
                     nonselflike_args,
-                    &EnumMatching(0, 1, &variants[0], Vec::new()),
+                    &EnumMatching(0, &variants[0], Vec::new()),
                 );
             }
         }
@@ -1316,7 +1328,7 @@ impl<'a> MethodDef<'a> {
                 // expressions for referencing every field of every
                 // Self arg, assuming all are instances of VariantK.
                 // Build up code associated with such a case.
-                let substructure = EnumMatching(index, variants.len(), variant, fields);
+                let substructure = EnumMatching(index, variant, fields);
                 let arm_expr = self
                     .call_substructure_method(
                         cx,
@@ -1344,7 +1356,7 @@ impl<'a> MethodDef<'a> {
                         trait_,
                         type_ident,
                         nonselflike_args,
-                        &EnumMatching(0, variants.len(), v, Vec::new()),
+                        &EnumMatching(0, v, Vec::new()),
                     )
                     .into_expr(cx, span),
                 )
@@ -1378,22 +1390,22 @@ impl<'a> MethodDef<'a> {
             cx.expr_match(span, match_arg, match_arms)
         };
 
-        // If the trait uses the tag and there are multiple variants, we need
-        // to add a tag check operation before the match. Otherwise, the match
+        // If the trait uses the discriminant and there are multiple variants, we need
+        // to add a discriminant check operation before the match. Otherwise, the match
         // is enough.
         if unify_fieldless_variants && variants.len() > 1 {
-            let (tag_field, mut tag_let_stmts) = get_tag_pieces(cx);
+            let (discr_field, mut discr_let_stmts) = get_discr_pieces(cx);
 
-            // Combine a tag check with the match.
-            let mut tag_check_plus_match = self.call_substructure_method(
+            // Combine a discriminant check with the match.
+            let mut discr_check_plus_match = self.call_substructure_method(
                 cx,
                 trait_,
                 type_ident,
                 nonselflike_args,
-                &EnumTag(tag_field, Some(get_match_expr(selflike_args))),
+                &EnumDiscr(discr_field, Some(get_match_expr(selflike_args))),
             );
-            tag_let_stmts.append(&mut tag_check_plus_match.0);
-            BlockOrExpr(tag_let_stmts, tag_check_plus_match.1)
+            discr_let_stmts.append(&mut discr_check_plus_match.0);
+            BlockOrExpr(discr_let_stmts, discr_check_plus_match.1)
         } else {
             BlockOrExpr(ThinVec::new(), Some(get_match_expr(selflike_args)))
         }
@@ -1401,7 +1413,7 @@ impl<'a> MethodDef<'a> {
 
     fn expand_static_enum_method_body(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         trait_: &TraitDef<'_>,
         enum_def: &EnumDef,
         type_ident: Ident,
@@ -1428,7 +1440,7 @@ impl<'a> MethodDef<'a> {
 
 // general helper methods.
 impl<'a> TraitDef<'a> {
-    fn summarise_struct(&self, cx: &mut ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
+    fn summarise_struct(&self, cx: &ExtCtxt<'_>, struct_def: &VariantData) -> StaticFields {
         let mut named_idents = Vec::new();
         let mut just_spans = Vec::new();
         for field in struct_def.fields() {
@@ -1439,7 +1451,10 @@ impl<'a> TraitDef<'a> {
             }
         }
 
-        let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
+        let is_tuple = match struct_def {
+            ast::VariantData::Tuple(..) => IsTuple::Yes,
+            _ => IsTuple::No,
+        };
         match (just_spans.is_empty(), named_idents.is_empty()) {
             (false, false) => cx
                 .dcx()
@@ -1455,7 +1470,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_patterns(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_path: ast::Path,
         struct_def: &'a VariantData,
         prefixes: &[String],
@@ -1474,11 +1489,7 @@ impl<'a> TraitDef<'a> {
                             struct_field.ident,
                             cx.pat(
                                 path.span,
-                                PatKind::Ident(
-                                    BindingAnnotation(by_ref, Mutability::Not),
-                                    path,
-                                    None,
-                                ),
+                                PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None),
                             ),
                         )
                     });
@@ -1548,7 +1559,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_pattern_fields(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         struct_def: &'a VariantData,
         prefixes: &[String],
     ) -> Vec<FieldInfo> {
@@ -1565,7 +1576,7 @@ impl<'a> TraitDef<'a> {
 
     fn create_struct_field_access_fields(
         &self,
-        cx: &mut ExtCtxt<'_>,
+        cx: &ExtCtxt<'_>,
         selflike_args: &[P<Expr>],
         struct_def: &'a VariantData,
         is_packed: bool,
@@ -1598,9 +1609,10 @@ impl<'a> TraitDef<'a> {
                         // Once use of `icu4x-0.9.0` has dropped sufficiently, this
                         // exception should be removed.
                         let is_simple_path = |ty: &P<ast::Ty>, sym| {
-                            if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind &&
-                                let [seg] = segments.as_slice() &&
-                                seg.ident.name == sym && seg.args.is_none()
+                            if let TyKind::Path(None, ast::Path { segments, .. }) = &ty.kind
+                                && let [seg] = segments.as_slice()
+                                && seg.ident.name == sym
+                                && seg.args.is_none()
                             {
                                 true
                             } else {
@@ -1608,8 +1620,8 @@ impl<'a> TraitDef<'a> {
                             }
                         };
 
-                        let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
-                            is_simple_path(ty, sym::u8)
+                        let exception = if let TyKind::Slice(ty) = &struct_field.ty.kind
+                            && is_simple_path(ty, sym::u8)
                         {
                             Some("byte")
                         } else if is_simple_path(&struct_field.ty, sym::str) {
@@ -1619,14 +1631,13 @@ impl<'a> TraitDef<'a> {
                         };
 
                         if let Some(ty) = exception {
-                            cx.sess.parse_sess.buffer_lint_with_diagnostic(
+                            cx.sess.psess.buffer_lint(
                                 BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
                                 sp,
                                 ast::CRATE_NODE_ID,
-                                format!(
-                                    "{ty} slice in a packed struct that derives a built-in trait"
-                                ),
-                                rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
+                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
+                                    ty: ty.to_string(),
+                                },
                             );
                         } else {
                             // Wrap the expression in `{...}`, causing a copy.
@@ -1645,7 +1656,7 @@ impl<'a> TraitDef<'a> {
 /// The function passed to `cs_fold` is called repeatedly with a value of this
 /// type. It describes one part of the code generation. The result is always an
 /// expression.
-pub enum CsFold<'a> {
+pub(crate) enum CsFold<'a> {
     /// The basic case: a field expression for one or more selflike args. E.g.
     /// for `PartialEq::eq` this is something like `self.x == other.x`.
     Single(&'a FieldInfo),
@@ -1660,15 +1671,15 @@ pub enum CsFold<'a> {
 
 /// Folds over fields, combining the expressions for each field in a sequence.
 /// Statics may not be folded over.
-pub fn cs_fold<F>(
+pub(crate) fn cs_fold<F>(
     use_foldl: bool,
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     trait_span: Span,
     substructure: &Substructure<'_>,
     mut f: F,
 ) -> P<Expr>
 where
-    F: FnMut(&mut ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
+    F: FnMut(&ExtCtxt<'_>, CsFold<'_>) -> P<Expr>,
 {
     match substructure.fields {
         EnumMatching(.., all_fields) | Struct(_, all_fields) => {
@@ -1695,16 +1706,16 @@ where
                 rest.iter().rfold(base_expr, op)
             }
         }
-        EnumTag(tag_field, match_expr) => {
-            let tag_check_expr = f(cx, CsFold::Single(tag_field));
+        EnumDiscr(discr_field, match_expr) => {
+            let discr_check_expr = f(cx, CsFold::Single(discr_field));
             if let Some(match_expr) = match_expr {
                 if use_foldl {
-                    f(cx, CsFold::Combine(trait_span, tag_check_expr, match_expr.clone()))
+                    f(cx, CsFold::Combine(trait_span, discr_check_expr, match_expr.clone()))
                 } else {
-                    f(cx, CsFold::Combine(trait_span, match_expr.clone(), tag_check_expr))
+                    f(cx, CsFold::Combine(trait_span, match_expr.clone(), discr_check_expr))
                 }
             } else {
-                tag_check_expr
+                discr_check_expr
             }
         }
         StaticEnum(..) | StaticStruct(..) => {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 603cefdd386..f01d586033e 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -1,28 +1,27 @@
 //! A mini version of ast::Ty, which is easier to use, and features an explicit `Self` type to use
 //! when specifying impls to be derived.
 
-pub use Ty::*;
+pub(crate) use Ty::*;
 
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, Expr, GenericArg, GenericParamKind, Generics, SelfKind};
 use rustc_expand::base::ExtCtxt;
 use rustc_span::source_map::respan;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
-use rustc_span::DUMMY_SP;
+use rustc_span::{Span, DUMMY_SP};
 use thin_vec::ThinVec;
 
 /// A path, e.g., `::std::option::Option::<i32>` (global). Has support
 /// for type parameters.
 #[derive(Clone)]
-pub struct Path {
+pub(crate) struct Path {
     path: Vec<Symbol>,
     params: Vec<Box<Ty>>,
     kind: PathKind,
 }
 
 #[derive(Clone)]
-pub enum PathKind {
+pub(crate) enum PathKind {
     Local,
     Global,
     Std,
@@ -73,7 +72,7 @@ impl Path {
 
 /// A type. Supports pointers, Self, and literals.
 #[derive(Clone)]
-pub enum Ty {
+pub(crate) enum Ty {
     Self_,
     /// A reference.
     Ref(Box<Ty>, ast::Mutability),
@@ -84,7 +83,7 @@ pub enum Ty {
     Unit,
 }
 
-pub fn self_ref() -> Ty {
+pub(crate) fn self_ref() -> Ty {
     Ref(Box::new(Self_), ast::Mutability::Not)
 }
 
@@ -164,7 +163,7 @@ fn mk_ty_param(
 
 /// Bounds on type parameters.
 #[derive(Clone)]
-pub struct Bounds {
+pub(crate) struct Bounds {
     pub bounds: Vec<(Symbol, Vec<Path>)>,
 }
 
@@ -197,7 +196,7 @@ impl Bounds {
     }
 }
 
-pub fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
+pub(crate) fn get_explicit_self(cx: &ExtCtxt<'_>, span: Span) -> (P<Expr>, ast::ExplicitSelf) {
     // This constructs a fresh `self` path.
     let self_path = cx.expr_self(span);
     let self_ty = respan(span, SelfKind::Region(None, ast::Mutability::Not));
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index dd6149cf614..dcd92819865 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -7,8 +7,8 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use thin_vec::thin_vec;
 
-pub fn expand_deriving_hash(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_deriving_hash(
+    cx: &ExtCtxt<'_>,
     span: Span,
     mitem: &MetaItem,
     item: &Annotatable,
@@ -46,11 +46,7 @@ pub fn expand_deriving_hash(
     hash_trait_def.expand(cx, mitem, item, push);
 }
 
-fn hash_substructure(
-    cx: &mut ExtCtxt<'_>,
-    trait_span: Span,
-    substr: &Substructure<'_>,
-) -> BlockOrExpr {
+fn hash_substructure(cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>) -> BlockOrExpr {
     let [state_expr] = substr.nonselflike_args else {
         cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
     };
@@ -70,9 +66,9 @@ fn hash_substructure(
                 fields.iter().map(|field| call_hash(field.span, field.self_expr.clone())).collect();
             (stmts, None)
         }
-        EnumTag(tag_field, match_expr) => {
-            assert!(tag_field.other_selflike_exprs.is_empty());
-            let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
+        EnumDiscr(discr_field, match_expr) => {
+            assert!(discr_field.other_selflike_exprs.is_empty());
+            let stmts = thin_vec![call_hash(discr_field.span, discr_field.self_expr.clone())];
             (stmts, match_expr.clone())
         }
         _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index a6f3252e7be..e3a93ae13e4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -20,27 +20,27 @@ macro path_std($($x:tt)*) {
     generic::ty::Path::new( pathvec_std!( $($x)* ) )
 }
 
-pub mod bounds;
-pub mod clone;
-pub mod debug;
-pub mod decodable;
-pub mod default;
-pub mod encodable;
-pub mod hash;
+pub(crate) mod bounds;
+pub(crate) mod clone;
+pub(crate) mod debug;
+pub(crate) mod decodable;
+pub(crate) mod default;
+pub(crate) mod encodable;
+pub(crate) mod hash;
 
 #[path = "cmp/eq.rs"]
-pub mod eq;
+pub(crate) mod eq;
 #[path = "cmp/ord.rs"]
-pub mod ord;
+pub(crate) mod ord;
 #[path = "cmp/partial_eq.rs"]
-pub mod partial_eq;
+pub(crate) mod partial_eq;
 #[path = "cmp/partial_ord.rs"]
-pub mod partial_ord;
+pub(crate) mod partial_ord;
 
-pub mod generic;
+pub(crate) mod generic;
 
 pub(crate) type BuiltinDeriveFn =
-    fn(&mut ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
+    fn(&ExtCtxt<'_>, Span, &MetaItem, &Annotatable, &mut dyn FnMut(Annotatable), bool);
 
 pub(crate) struct BuiltinDerive(pub(crate) BuiltinDeriveFn);
 
@@ -117,12 +117,14 @@ fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> {
 }
 
 fn assert_ty_bounds(
-    cx: &mut ExtCtxt<'_>,
+    cx: &ExtCtxt<'_>,
     stmts: &mut ThinVec<ast::Stmt>,
     ty: P<ast::Ty>,
     span: Span,
     assert_path: &[Symbol],
 ) {
+    // Deny anonymous structs or unions to avoid weird errors.
+    assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
     // Generate statement `let _: assert_path<ty>;`.
     let span = cx.with_def_site_ctxt(span);
     let assert_path = cx.path_all(span, true, cx.std_path(assert_path), vec![GenericArg::Type(ty)]);
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
index 1e1dadab480..cc385bade47 100644
--- a/compiler/rustc_builtin_macros/src/edition_panic.rs
+++ b/compiler/rustc_builtin_macros/src/edition_panic.rs
@@ -16,11 +16,11 @@ use rustc_span::Span;
 ///
 /// `$crate` will refer to either the `std` or `core` crate depending on which
 /// one we're expanding from.
-pub fn expand_panic<'cx>(
+pub(crate) fn expand_panic<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
     expand(mac, cx, sp, tts)
 }
@@ -29,24 +29,24 @@ pub fn expand_panic<'cx>(
 /// - `$crate::panic::unreachable_2015!(...)` or
 /// - `$crate::panic::unreachable_2021!(...)`
 /// depending on the edition.
-pub fn expand_unreachable<'cx>(
+pub(crate) fn expand_unreachable<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
     expand(mac, cx, sp, tts)
 }
 
 fn expand<'cx>(
     mac: rustc_span::Symbol,
-    cx: &'cx mut ExtCtxt<'_>,
+    cx: &'cx ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let sp = cx.with_call_site_ctxt(sp);
 
-    MacEager::expr(
+    ExpandResult::Ready(MacEager::expr(
         cx.expr(
             sp,
             ExprKind::MacCall(P(MacCall {
@@ -66,10 +66,10 @@ fn expand<'cx>(
                 }),
             })),
         ),
-    )
+    ))
 }
 
-pub fn use_panic_2021(mut span: Span) -> bool {
+pub(crate) fn use_panic_2021(mut span: Span) -> bool {
     // To determine the edition, we check the first span up the expansion
     // stack that does not have #[allow_internal_unstable(edition_panic)].
     // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index a0fd0e3f9be..b03e14cf263 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -3,38 +3,44 @@
 // interface.
 //
 
+use crate::errors;
+use crate::util::{expr_to_string, get_exprs_from_tts, get_single_str_from_tts};
+use rustc_ast::token::{self, LitKind};
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{self as ast, AstDeref, GenericArg};
-use rustc_expand::base::{self, *};
+use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use std::env;
+use std::env::VarError;
 use thin_vec::thin_vec;
 
-use crate::errors;
-
-fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Option<Symbol> {
+fn lookup_env<'cx>(cx: &'cx ExtCtxt<'_>, var: Symbol) -> Result<Symbol, VarError> {
     let var = var.as_str();
     if let Some(value) = cx.sess.opts.logical_env.get(var) {
-        return Some(Symbol::intern(value));
+        return Ok(Symbol::intern(value));
     }
     // If the environment variable was not defined with the `--env-set` option, we try to retrieve it
     // from rustc's environment.
-    env::var(var).ok().as_deref().map(Symbol::intern)
+    Ok(Symbol::intern(&env::var(var)?))
 }
 
-pub fn expand_option_env<'cx>(
+pub(crate) fn expand_option_env<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    let Some(var) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
-        return DummyResult::any(sp);
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "option_env!") else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
+        Ok(var) => var,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
     let sp = cx.with_def_site_ctxt(sp);
-    let value = lookup_env(cx, var);
-    cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+    let value = lookup_env(cx, var).ok();
+    cx.sess.psess.env_depinfo.borrow_mut().insert((var, value));
     let e = match value {
         None => {
             let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
@@ -46,7 +52,7 @@ pub fn expand_option_env<'cx>(
                     sp,
                     cx.ty_ident(sp, Ident::new(sym::str, sp)),
                     Some(lt),
-                    ast::Mutability::Not,
+                    Mutability::Not,
                 ))],
             ))
         }
@@ -56,71 +62,91 @@ pub fn expand_option_env<'cx>(
             thin_vec![cx.expr_str(sp, value)],
         ),
     };
-    MacEager::expr(e)
+    ExpandResult::Ready(MacEager::expr(e))
 }
 
-pub fn expand_env<'cx>(
+pub(crate) fn expand_env<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
-    let mut exprs = match get_exprs_from_tts(cx, tts) {
-        Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
-            cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
-            return DummyResult::any(sp);
+) -> MacroExpanderResult<'cx> {
+    let ExpandResult::Ready(mac) = get_exprs_from_tts(cx, tts) else {
+        return ExpandResult::Retry(());
+    };
+    let mut exprs = match mac {
+        Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => {
+            let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
-        None => return DummyResult::any(sp),
-        Some(exprs) => exprs.into_iter(),
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
+        Ok(exprs) => exprs.into_iter(),
     };
 
     let var_expr = exprs.next().unwrap();
-    let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else {
-        return DummyResult::any(sp);
+    let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal")
+    else {
+        return ExpandResult::Retry(());
+    };
+    let var = match mac {
+        Ok((var, _)) => var,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
 
     let custom_msg = match exprs.next() {
         None => None,
-        Some(second) => match expr_to_string(cx, second, "expected string literal") {
-            None => return DummyResult::any(sp),
-            Some((s, _)) => Some(s),
-        },
+        Some(second) => {
+            let ExpandResult::Ready(mac) = expr_to_string(cx, second, "expected string literal")
+            else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok((s, _)) => Some(s),
+                Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
+            }
+        }
     };
 
     let span = cx.with_def_site_ctxt(sp);
     let value = lookup_env(cx, var);
-    cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+    cx.sess.psess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied()));
     let e = match value {
-        None => {
-            let ast::ExprKind::Lit(ast::token::Lit {
-                kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..),
-                symbol,
-                ..
+        Err(err) => {
+            let ExprKind::Lit(token::Lit {
+                kind: LitKind::Str | LitKind::StrRaw(..), symbol, ..
             }) = &var_expr.kind
             else {
                 unreachable!("`expr_to_string` ensures this is a string lit")
             };
 
-            if let Some(msg_from_user) = custom_msg {
-                cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
-            } else if is_cargo_env_var(var.as_str()) {
-                cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
-                    span,
-                    var: *symbol,
-                    var_expr: var_expr.ast_deref(),
-                });
-            } else {
-                cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
-                    span,
-                    var: *symbol,
-                    var_expr: var_expr.ast_deref(),
-                });
-            }
+            let guar = match err {
+                VarError::NotPresent => {
+                    if let Some(msg_from_user) = custom_msg {
+                        cx.dcx()
+                            .emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user })
+                    } else if is_cargo_env_var(var.as_str()) {
+                        cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
+                            span,
+                            var: *symbol,
+                            var_expr: var_expr.ast_deref(),
+                        })
+                    } else {
+                        cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
+                            span,
+                            var: *symbol,
+                            var_expr: var_expr.ast_deref(),
+                        })
+                    }
+                }
+                VarError::NotUnicode(_) => {
+                    cx.dcx().emit_err(errors::EnvNotUnicode { span, var: *symbol })
+                }
+            };
 
-            return DummyResult::any(sp);
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
-        Some(value) => cx.expr_str(span, value),
+        Ok(value) => cx.expr_str(span, value),
     };
-    MacEager::expr(e)
+    ExpandResult::Ready(MacEager::expr(e))
 }
 
 /// Returns `true` if an environment variable from `env!` is one used by Cargo.
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 8d2e06bf30d..d157703723b 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1,6 +1,6 @@
 use rustc_errors::{
-    codes::*, AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, EmissionGuarantee,
-    IntoDiagnostic, Level, MultiSpan, SingleLabelManySpans, SubdiagnosticMessageOp,
+    codes::*, Diag, DiagCtxt, Diagnostic, EmissionGuarantee, Level, MultiSpan,
+    SingleLabelManySpans, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{symbol::Ident, Span, Symbol};
@@ -137,27 +137,6 @@ pub(crate) struct BenchSig {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_test_arg_non_lifetime)]
-pub(crate) struct TestArgNonLifetime {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_should_panic)]
-pub(crate) struct ShouldPanic {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_test_args)]
-pub(crate) struct TestArgs {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(builtin_macros_alloc_must_statics)]
 pub(crate) struct AllocMustStatics {
     #[primary_span]
@@ -446,14 +425,14 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
 }
 
 // Hand-written implementation to support custom user messages.
-impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefinedWithUserMessage {
+impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage {
     #[track_caller]
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
+    fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
         #[expect(
             rustc::untranslatable_diagnostic,
             reason = "cannot translate user-provided messages"
         )]
-        let mut diag = DiagnosticBuilder::new(dcx, level, self.msg_from_user.to_string());
+        let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string());
         diag.span(self.span);
         diag
     }
@@ -480,6 +459,14 @@ pub(crate) enum EnvNotDefined<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_env_not_unicode)]
+pub(crate) struct EnvNotUnicode {
+    #[primary_span]
+    pub(crate) span: Span,
+    pub(crate) var: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_format_requires_string)]
 pub(crate) struct FormatRequiresString {
     #[primary_span]
@@ -592,7 +579,7 @@ pub(crate) struct FormatUnknownTrait<'a> {
     style = "tool-only",
     applicability = "maybe-incorrect"
 )]
-pub struct FormatUnknownTraitSugg {
+pub(crate) struct FormatUnknownTraitSugg {
     #[primary_span]
     pub span: Span,
     pub fmt: &'static str,
@@ -610,8 +597,12 @@ pub(crate) struct FormatUnusedArg {
 
 // Allow the singular form to be a subdiagnostic of the multiple-unused
 // form of diagnostic.
-impl AddToDiagnostic for FormatUnusedArg {
-    fn add_to_diagnostic_with<F: SubdiagnosticMessageOp>(self, diag: &mut Diagnostic, f: F) {
+impl Subdiagnostic for FormatUnusedArg {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        f: &F,
+    ) {
         diag.arg("named", self.named);
         let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
         diag.span_label(self.span, msg);
@@ -784,6 +775,13 @@ pub(crate) struct AsmNoReturn {
 }
 
 #[derive(Diagnostic)]
+#[diag(builtin_macros_asm_mayunwind)]
+pub(crate) struct AsmMayUnwind {
+    #[primary_span]
+    pub(crate) labels_sp: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
 #[diag(builtin_macros_global_asm_clobber_abi)]
 pub(crate) struct GlobalAsmClobberAbi {
     #[primary_span]
@@ -795,8 +793,8 @@ pub(crate) struct AsmClobberNoReg {
     pub(crate) clobbers: Vec<Span>,
 }
 
-impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
-    fn into_diagnostic(self, dcx: &'a DiagCtxt, level: Level) -> DiagnosticBuilder<'a, G> {
+impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AsmClobberNoReg {
+    fn into_diag(self, dcx: &'a DiagCtxt, level: Level) -> Diag<'a, G> {
         // eager translation as `span_labels` takes `AsRef<str>`
         let lbl1 = dcx.eagerly_translate_to_string(
             crate::fluent_generated::builtin_macros_asm_clobber_abi,
@@ -806,14 +804,10 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
             crate::fluent_generated::builtin_macros_asm_clobber_outputs,
             [].into_iter(),
         );
-        DiagnosticBuilder::new(
-            dcx,
-            level,
-            crate::fluent_generated::builtin_macros_asm_clobber_no_reg,
-        )
-        .with_span(self.spans.clone())
-        .with_span_labels(self.clobbers, &lbl1)
-        .with_span_labels(self.spans, &lbl2)
+        Diag::new(dcx, level, crate::fluent_generated::builtin_macros_asm_clobber_no_reg)
+            .with_span(self.spans.clone())
+            .with_span_labels(self.clobbers, &lbl1)
+            .with_span_labels(self.spans, &lbl2)
     }
 }
 
@@ -848,3 +842,26 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister {
     #[primary_span]
     pub(crate) span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_expected_comma_in_list)]
+pub(crate) struct ExpectedCommaInList {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_only_one_argument)]
+pub(crate) struct OnlyOneArgument<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_takes_no_arguments)]
+pub(crate) struct TakesNoArguments<'a> {
+    #[primary_span]
+    pub span: Span,
+    pub name: &'a str,
+}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index b66f7111ff0..5cb0407bd59 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -1,3 +1,5 @@
+use crate::errors;
+use crate::util::expr_to_spanned_string;
 use parse::Position::ArgumentNamed;
 use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::TokenStream;
@@ -5,17 +7,16 @@ use rustc_ast::{token, StmtKind};
 use rustc_ast::{
     Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
     FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
-    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
+    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered,
 };
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan, PResult, SingleLabelManySpans};
-use rustc_expand::base::{self, *};
+use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
+use rustc_expand::base::*;
+use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
+use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
 use rustc_parse_format as parse;
 use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::{BytePos, InnerSpan, Span};
-
-use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
-use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
+use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
 
 // The format_args!() macro is expanded in three steps:
 //  1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
@@ -37,8 +38,7 @@ enum PositionUsedAs {
 }
 use PositionUsedAs::*;
 
-use crate::errors;
-
+#[derive(Debug)]
 struct MacroInput {
     fmtstr: P<Expr>,
     args: FormatArguments,
@@ -63,7 +63,7 @@ struct MacroInput {
 /// ```text
 /// Ok((fmtstr, parsed arguments))
 /// ```
-fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
+fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> {
     let mut args = FormatArguments::new();
 
     let mut p = ecx.new_parser_from_tts(tts);
@@ -111,9 +111,8 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
                         _ => return Err(err),
                     }
                 }
-                Ok(recovered) => {
-                    assert!(recovered);
-                }
+                Ok(Recovered::Yes(_)) => (),
+                Ok(Recovered::No) => unreachable!(),
             }
         }
         first = false;
@@ -160,51 +159,61 @@ fn make_format_args(
     ecx: &mut ExtCtxt<'_>,
     input: MacroInput,
     append_newline: bool,
-) -> Result<FormatArgs, ()> {
+) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
     let msg = "format argument must be a string literal";
     let unexpanded_fmt_span = input.fmtstr.span;
 
     let MacroInput { fmtstr: efmt, mut args, is_direct_literal } = input;
 
-    let (fmt_str, fmt_style, fmt_span) = match expr_to_spanned_string(ecx, efmt.clone(), msg) {
-        Ok(mut fmt) if append_newline => {
-            fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
-            fmt
-        }
-        Ok(fmt) => fmt,
-        Err(err) => {
-            if let Some((mut err, suggested)) = err {
-                if !suggested {
-                    if let ExprKind::Block(block, None) = &efmt.kind
-                        && block.stmts.len() == 1
-                        && let StmtKind::Expr(expr) = &block.stmts[0].kind
-                        && let ExprKind::Path(None, path) = &expr.kind
-                        && path.is_potential_trivial_const_arg()
-                    {
-                        err.multipart_suggestion(
-                            "quote your inlined format argument to use as string literal",
-                            vec![
-                                (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
-                                (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
-                            ],
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        let sugg_fmt = match args.explicit_args().len() {
-                            0 => "{}".to_string(),
-                            _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())),
-                        };
-                        err.span_suggestion(
-                            unexpanded_fmt_span.shrink_to_lo(),
-                            "you might be missing a string literal to format with",
-                            format!("\"{sugg_fmt}\", "),
-                            Applicability::MaybeIncorrect,
-                        );
+    let (fmt_str, fmt_style, fmt_span) = {
+        let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, efmt.clone(), msg) else {
+            return ExpandResult::Retry(());
+        };
+        match mac {
+            Ok(mut fmt) if append_newline => {
+                fmt.0 = Symbol::intern(&format!("{}\n", fmt.0));
+                fmt
+            }
+            Ok(fmt) => fmt,
+            Err(err) => {
+                let guar = match err {
+                    Ok((mut err, suggested)) => {
+                        if !suggested {
+                            if let ExprKind::Block(block, None) = &efmt.kind
+                                && block.stmts.len() == 1
+                                && let StmtKind::Expr(expr) = &block.stmts[0].kind
+                                && let ExprKind::Path(None, path) = &expr.kind
+                                && path.is_potential_trivial_const_arg()
+                            {
+                                err.multipart_suggestion(
+                                    "quote your inlined format argument to use as string literal",
+                                    vec![
+                                        (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()),
+                                        (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()),
+                                    ],
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                let sugg_fmt = match args.explicit_args().len() {
+                                    0 => "{}".to_string(),
+                                    _ => {
+                                        format!("{}{{}}", "{} ".repeat(args.explicit_args().len()))
+                                    }
+                                };
+                                err.span_suggestion(
+                                    unexpanded_fmt_span.shrink_to_lo(),
+                                    "you might be missing a string literal to format with",
+                                    format!("\"{sugg_fmt}\", "),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                        err.emit()
                     }
-                }
-                err.emit();
+                    Err(guar) => guar,
+                };
+                return ExpandResult::Ready(Err(guar));
             }
-            return Err(());
         }
     };
 
@@ -293,11 +302,11 @@ fn make_format_args(
                 }
             }
         }
-        ecx.dcx().emit_err(e);
-        return Err(());
+        let guar = ecx.dcx().emit_err(e);
+        return ExpandResult::Ready(Err(guar));
     }
 
-    let to_span = |inner_span: rustc_parse_format::InnerSpan| {
+    let to_span = |inner_span: parse::InnerSpan| {
         is_source_literal.then(|| {
             fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
         })
@@ -305,7 +314,7 @@ fn make_format_args(
 
     let mut used = vec![false; args.explicit_args().len()];
     let mut invalid_refs = Vec::new();
-    let mut numeric_refences_to_named_arg = Vec::new();
+    let mut numeric_references_to_named_arg = Vec::new();
 
     enum ArgRef<'a> {
         Index(usize),
@@ -326,7 +335,7 @@ fn make_format_args(
                     used[index] = true;
                     if arg.kind.ident().is_some() {
                         // This was a named argument, but it was used as a positional argument.
-                        numeric_refences_to_named_arg.push((index, span, used_as));
+                        numeric_references_to_named_arg.push((index, span, used_as));
                     }
                     Ok(index)
                 } else {
@@ -353,9 +362,9 @@ fn make_format_args(
                     } else {
                         // For the moment capturing variables from format strings expanded from macros is
                         // disabled (see RFC #2795)
-                        ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
+                        let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
                         unnamed_arg_after_named_arg = true;
-                        DummyResult::raw_expr(span, true)
+                        DummyResult::raw_expr(span, Some(guar))
                     };
                     Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
                 }
@@ -534,7 +543,7 @@ fn make_format_args(
     // Only check for unused named argument names if there are no other errors to avoid causing
     // too much noise in output errors, such as when a named argument is entirely unused.
     if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg {
-        for &(index, span, used_as) in &numeric_refences_to_named_arg {
+        for &(index, span, used_as) in &numeric_references_to_named_arg {
             let (position_sp_to_replace, position_sp_for_msg) = match used_as {
                 Placeholder(pspan) => (span, pspan),
                 Precision => {
@@ -547,10 +556,9 @@ fn make_format_args(
             let arg_name = args.explicit_args()[index].kind.ident().unwrap();
             ecx.buffered_early_lint.push(BufferedEarlyLint {
                 span: arg_name.span.into(),
-                msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
-                diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
                     position_sp_to_replace,
                     position_sp_for_msg,
                     named_arg_sp: arg_name.span,
@@ -561,13 +569,13 @@ fn make_format_args(
         }
     }
 
-    Ok(FormatArgs { span: fmt_span, template, arguments: args })
+    ExpandResult::Ready(Ok(FormatArgs { span: fmt_span, template, arguments: args }))
 }
 
 fn invalid_placeholder_type_error(
     ecx: &ExtCtxt<'_>,
     ty: &str,
-    ty_span: Option<rustc_parse_format::InnerSpan>,
+    ty_span: Option<parse::InnerSpan>,
     fmt_span: Span,
 ) {
     let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));
@@ -593,7 +601,7 @@ fn invalid_placeholder_type_error(
 }
 
 fn report_missing_placeholders(
-    ecx: &mut ExtCtxt<'_>,
+    ecx: &ExtCtxt<'_>,
     unused: Vec<(Span, bool)>,
     used: &[bool],
     args: &FormatArguments,
@@ -723,11 +731,11 @@ fn report_missing_placeholders(
 /// This function detects and reports unused format!() arguments that are
 /// redundant due to implicit captures (e.g. `format!("{x}", x)`).
 fn report_redundant_format_arguments<'a>(
-    ecx: &mut ExtCtxt<'a>,
+    ecx: &ExtCtxt<'a>,
     args: &FormatArguments,
     used: &[bool],
     placeholders: Vec<(Span, &str)>,
-) -> Option<DiagnosticBuilder<'a>> {
+) -> Option<Diag<'a>> {
     let mut fmt_arg_indices = vec![];
     let mut args_spans = vec![];
     let mut fmt_spans = vec![];
@@ -795,7 +803,7 @@ fn report_redundant_format_arguments<'a>(
 /// there are named arguments or numbered positional arguments in the
 /// format string.
 fn report_invalid_references(
-    ecx: &mut ExtCtxt<'_>,
+    ecx: &ExtCtxt<'_>,
     invalid_refs: &[(usize, Option<Span>, PositionUsedAs, FormatArgPositionKind)],
     template: &[FormatArgsPiece],
     fmt_span: Span,
@@ -969,35 +977,39 @@ fn expand_format_args_impl<'cx>(
     mut sp: Span,
     tts: TokenStream,
     nl: bool,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     sp = ecx.with_def_site_ctxt(sp);
-    match parse_args(ecx, sp, tts) {
+    ExpandResult::Ready(match parse_args(ecx, sp, tts) {
         Ok(input) => {
-            if let Ok(format_args) = make_format_args(ecx, input, nl) {
-                MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
-            } else {
-                MacEager::expr(DummyResult::raw_expr(sp, true))
+            let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
+                return ExpandResult::Retry(());
+            };
+            match mac {
+                Ok(format_args) => {
+                    MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
+                }
+                Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))),
             }
         }
         Err(err) => {
-            err.emit();
-            DummyResult::any(sp)
+            let guar = err.emit();
+            DummyResult::any(sp, guar)
         }
-    }
+    })
 }
 
-pub fn expand_format_args<'cx>(
+pub(crate) fn expand_format_args<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     expand_format_args_impl(ecx, sp, tts, false)
 }
 
-pub fn expand_format_args_nl<'cx>(
+pub(crate) fn expand_format_args_nl<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     expand_format_args_impl(ecx, sp, tts, true)
 }
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 307e582d65e..bc2c6def68a 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -263,13 +263,13 @@ pub(crate) mod printf {
     }
 
     impl Num {
-        fn from_str(s: &str, arg: Option<&str>) -> Self {
+        fn from_str(s: &str, arg: Option<&str>) -> Option<Self> {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
+                arg.parse().ok().map(|arg| Num::Arg(arg))
             } else if s == "*" {
-                Num::Next
+                Some(Num::Next)
             } else {
-                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
+                s.parse().ok().map(|num| Num::Num(num))
             }
         }
 
@@ -421,7 +421,10 @@ pub(crate) mod printf {
                             state = Prec;
                             parameter = None;
                             flags = "";
-                            width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                            width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                            if width.is_none() {
+                                return fallback();
+                            }
                             move_to!(end);
                         }
                         // It's invalid, is what it is.
@@ -452,7 +455,10 @@ pub(crate) mod printf {
                 '1'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
-                    width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                    if width.is_none() {
+                        return fallback();
+                    }
                     move_to!(end);
                 }
                 _ => {
@@ -468,7 +474,7 @@ pub(crate) mod printf {
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
-                    width = Some(Num::from_str("", Some(at.slice_between(end).unwrap())));
+                    width = Num::from_str("", at.slice_between(end));
                     move_to!(end2);
                 }
                 _ => {
@@ -500,7 +506,7 @@ pub(crate) mod printf {
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
-                            precision = Some(Num::from_str("*", next.slice_between(end)));
+                            precision = Num::from_str("*", next.slice_between(end));
                             move_to!(end2);
                         }
                         _ => {
@@ -513,7 +519,7 @@ pub(crate) mod printf {
                 '0'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
-                    precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    precision = at.slice_between(end).and_then(|num| Num::from_str(num, None));
                     move_to!(end);
                 }
                 _ => return fallback(),
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 099defd511b..b44ff979303 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -6,13 +6,13 @@ use rustc_ast::expand::allocator::{
 };
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Safety, Stmt, Ty, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
 use thin_vec::{thin_vec, ThinVec};
 
-pub fn expand(
+pub(crate) fn expand(
     ecx: &mut ExtCtxt<'_>,
     _span: Span,
     meta_item: &ast::MetaItem,
@@ -73,7 +73,7 @@ impl AllocFnFactory<'_, '_> {
         let result = self.call_allocator(method.name, args);
         let output_ty = self.ret_ty(&method.output);
         let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
-        let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
+        let header = FnHeader { safety: Safety::Unsafe(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header, span: self.span };
         let body = Some(self.cx.block_expr(result));
         let kind = ItemKind::Fn(Box::new(Fn {
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index d30ccab2394..744c7f9d090 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -15,14 +15,11 @@
 #![feature(lint_reasons)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
+#![feature(try_blocks)]
 
 extern crate proc_macro;
 
-#[macro_use]
-extern crate tracing;
-
 use crate::deriving::*;
-
 use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
 use rustc_expand::proc_macro::BangProcMacro;
 use rustc_span::symbol::sym;
@@ -45,17 +42,17 @@ mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
+mod pattern_type;
 mod source_util;
 mod test;
 mod trace_macros;
-mod type_ascribe;
-mod util;
 
 pub mod asm;
 pub mod cmdline_attrs;
 pub mod proc_macro_harness;
 pub mod standard_library_imports;
 pub mod test_harness;
+pub mod util;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
@@ -95,10 +92,10 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
         option_env: env::expand_option_env,
+        pattern_type: pattern_type::expand,
         std_panic: edition_panic::expand_panic,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
-        type_ascribe: type_ascribe::expand_type_ascribe,
         unreachable: edition_panic::expand_unreachable,
         // tidy-alphabetical-end
     }
@@ -108,8 +105,8 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         bench: test::expand_bench,
         cfg_accessible: cfg_accessible::Expander,
         cfg_eval: cfg_eval::expand,
-        derive: derive::Expander(false),
-        derive_const: derive::Expander(true),
+        derive: derive::Expander { is_const: false },
+        derive_const: derive::Expander { is_const: true },
         global_allocator: global_allocator::expand,
         test: test::expand_test,
         test_case: test::expand_test_case,
diff --git a/compiler/rustc_builtin_macros/src/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs
index ede34a76125..205f21ae7c9 100644
--- a/compiler/rustc_builtin_macros/src/log_syntax.rs
+++ b/compiler/rustc_builtin_macros/src/log_syntax.rs
@@ -1,14 +1,14 @@
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_expand::base;
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 
-pub fn expand_log_syntax<'cx>(
-    _cx: &'cx mut base::ExtCtxt<'_>,
+pub(crate) fn expand_log_syntax<'cx>(
+    _cx: &'cx mut ExtCtxt<'_>,
     sp: rustc_span::Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     println!("{}", pprust::tts_to_string(&tts));
 
     // any so that `log_syntax` can be invoked as an expression and item.
-    base::DummyResult::any_valid(sp)
+    ExpandResult::Ready(DummyResult::any_valid(sp))
 }
diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
new file mode 100644
index 00000000000..31f5656df13
--- /dev/null
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -0,0 +1,29 @@
+use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty};
+use rustc_errors::PResult;
+use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
+use rustc_span::{sym, Span};
+
+pub(crate) fn expand<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> MacroExpanderResult<'cx> {
+    let (ty, pat) = match parse_pat_ty(cx, tts) {
+        Ok(parsed) => parsed,
+        Err(err) => {
+            return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
+        }
+    };
+
+    ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat))))
+}
+
+fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> {
+    let mut parser = cx.new_parser_from_tts(stream);
+
+    let ty = parser.parse_ty()?;
+    parser.eat_keyword(sym::is);
+    let pat = parser.parse_pat_no_top_alt(None, None)?;
+
+    Ok((ty, pat))
+}
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 43d13569d1e..dc1d82df0c3 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -1,17 +1,25 @@
+use crate::util::{
+    check_zero_tts, get_single_str_from_tts, get_single_str_spanned_from_tts, parse_expr,
+};
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast_pretty::pprust;
-use rustc_expand::base::{self, *};
+use rustc_data_structures::sync::Lrc;
+use rustc_expand::base::{
+    resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
+};
 use rustc_expand::module::DirOwnership;
-use rustc_parse::new_parser_from_file;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::parser::{ForceCollect, Parser};
+use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
+use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Pos, Span};
-
 use smallvec::SmallVec;
+use std::path::{Path, PathBuf};
 use std::rc::Rc;
 
 // These macros all relate to the file system; they either return
@@ -19,102 +27,106 @@ use std::rc::Rc;
 // a given file into the current one.
 
 /// line!(): expands to the current line number
-pub fn expand_line(
+pub(crate) fn expand_line(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    base::check_zero_tts(cx, sp, tts, "line!");
+    check_zero_tts(cx, sp, tts, "line!");
 
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
-    base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32))
+    ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.line as u32)))
 }
 
 /* column!(): expands to the current column number */
-pub fn expand_column(
+pub(crate) fn expand_column(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    base::check_zero_tts(cx, sp, tts, "column!");
+    check_zero_tts(cx, sp, tts, "column!");
 
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
-    base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
+    ExpandResult::Ready(MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)))
 }
 
 /// file!(): expands to the current filename */
 /// The source_file (`loc.file`) contains a bunch more information we could spit
 /// out if we wanted.
-pub fn expand_file(
+pub(crate) fn expand_file(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    base::check_zero_tts(cx, sp, tts, "file!");
+    check_zero_tts(cx, sp, tts, "file!");
 
     let topmost = cx.expansion_cause().unwrap_or(sp);
     let loc = cx.source_map().lookup_char_pos(topmost.lo());
 
     use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt};
-    base::MacEager::expr(cx.expr_str(
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(
         topmost,
         Symbol::intern(
             &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
         ),
-    ))
+    )))
 }
 
-pub fn expand_stringify(
+pub(crate) fn expand_stringify(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
     let s = pprust::tts_to_string(&tts);
-    base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s)))
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))))
 }
 
-pub fn expand_mod(
+pub(crate) fn expand_mod(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    base::check_zero_tts(cx, sp, tts, "module_path!");
+    check_zero_tts(cx, sp, tts, "module_path!");
     let mod_path = &cx.current_expansion.module.mod_path;
     let string = mod_path.iter().map(|x| x.to_string()).collect::<Vec<String>>().join("::");
 
-    base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string)))
+    ExpandResult::Ready(MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))))
 }
 
 /// include! : parse the given file as an expr
 /// This is generally a bad idea because it's going to behave
 /// unhygienically.
-pub fn expand_include<'cx>(
+pub(crate) fn expand_include<'cx>(
     cx: &'cx mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'cx> {
+) -> MacroExpanderResult<'cx> {
     let sp = cx.with_def_site_ctxt(sp);
-    let Some(file) = get_single_str_from_tts(cx, sp, tts, "include!") else {
-        return DummyResult::any(sp);
+    let ExpandResult::Ready(mac) = get_single_str_from_tts(cx, sp, tts, "include!") else {
+        return ExpandResult::Retry(());
+    };
+    let file = match mac {
+        Ok(file) => file,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
     // The file will be added to the code map by the parser
     let file = match resolve_path(&cx.sess, file.as_str(), sp) {
         Ok(f) => f,
         Err(err) => {
-            err.emit();
-            return DummyResult::any(sp);
+            let guar = err.emit();
+            return ExpandResult::Ready(DummyResult::any(sp, guar));
         }
     };
-    let p = new_parser_from_file(cx.parse_sess(), &file, Some(sp));
+    let p = unwrap_or_emit_fatal(new_parser_from_file(cx.psess(), &file, Some(sp)));
 
     // If in the included file we have e.g., `mod bar;`,
     // then the path of `bar.rs` should be relative to the directory of `file`.
@@ -124,25 +136,25 @@ pub fn expand_include<'cx>(
     cx.current_expansion.module = Rc::new(cx.current_expansion.module.with_dir_path(dir_path));
     cx.current_expansion.dir_ownership = DirOwnership::Owned { relative: None };
 
-    struct ExpandResult<'a> {
+    struct ExpandInclude<'a> {
         p: Parser<'a>,
         node_id: ast::NodeId,
     }
-    impl<'a> base::MacResult for ExpandResult<'a> {
-        fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
-            let r = base::parse_expr(&mut self.p)?;
+    impl<'a> MacResult for ExpandInclude<'a> {
+        fn make_expr(mut self: Box<ExpandInclude<'a>>) -> Option<P<ast::Expr>> {
+            let expr = parse_expr(&mut self.p).ok()?;
             if self.p.token != token::Eof {
-                self.p.sess.buffer_lint(
+                self.p.psess.buffer_lint(
                     INCOMPLETE_INCLUDE,
                     self.p.token.span,
                     self.node_id,
-                    "include macro expected single expression in source",
+                    BuiltinLintDiag::IncompleteInclude,
                 );
             }
-            Some(r)
+            Some(expr)
         }
 
-        fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
+        fn make_items(mut self: Box<ExpandInclude<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
             let mut ret = SmallVec::new();
             loop {
                 match self.p.parse_item(ForceCollect::No) {
@@ -166,68 +178,166 @@ pub fn expand_include<'cx>(
         }
     }
 
-    Box::new(ExpandResult { p, node_id: cx.current_expansion.lint_node_id })
+    ExpandResult::Ready(Box::new(ExpandInclude { p, node_id: cx.current_expansion.lint_node_id }))
 }
 
 /// `include_str!`: read the given file, insert it as a literal string expr
-pub fn expand_include_str(
+pub(crate) fn expand_include_str(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else {
-        return DummyResult::any(sp);
+    let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_str!")
+    else {
+        return ExpandResult::Retry(());
     };
-    let file = match resolve_path(&cx.sess, file.as_str(), sp) {
-        Ok(f) => f,
-        Err(err) => {
-            err.emit();
-            return DummyResult::any(sp);
-        }
+    let (path, path_span) = match mac {
+        Ok(res) => res,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
     };
-    match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => match std::str::from_utf8(&bytes) {
+    ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
+        Ok((bytes, bsp)) => match std::str::from_utf8(&bytes) {
             Ok(src) => {
                 let interned_src = Symbol::intern(src);
-                base::MacEager::expr(cx.expr_str(sp, interned_src))
+                MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src))
             }
             Err(_) => {
-                cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
-                DummyResult::any(sp)
+                let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file"));
+                DummyResult::any(sp, guar)
             }
         },
-        Err(e) => {
-            cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            DummyResult::any(sp)
-        }
-    }
+        Err(dummy) => dummy,
+    })
 }
 
-pub fn expand_include_bytes(
+pub(crate) fn expand_include_bytes(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let sp = cx.with_def_site_ctxt(sp);
-    let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else {
-        return DummyResult::any(sp);
+    let ExpandResult::Ready(mac) = get_single_str_spanned_from_tts(cx, sp, tts, "include_bytes!")
+    else {
+        return ExpandResult::Retry(());
     };
-    let file = match resolve_path(&cx.sess, file.as_str(), sp) {
-        Ok(f) => f,
+    let (path, path_span) = match mac {
+        Ok(res) => res,
+        Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
+    };
+    ExpandResult::Ready(match load_binary_file(cx, path.as_str().as_ref(), sp, path_span) {
+        Ok((bytes, _bsp)) => {
+            // Don't care about getting the span for the raw bytes,
+            // because the console can't really show them anyway.
+            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
+            MacEager::expr(expr)
+        }
+        Err(dummy) => dummy,
+    })
+}
+
+fn load_binary_file(
+    cx: &ExtCtxt<'_>,
+    original_path: &Path,
+    macro_span: Span,
+    path_span: Span,
+) -> Result<(Lrc<[u8]>, Span), Box<dyn MacResult>> {
+    let resolved_path = match resolve_path(&cx.sess, original_path, macro_span) {
+        Ok(path) => path,
         Err(err) => {
-            err.emit();
-            return DummyResult::any(sp);
+            let guar = err.emit();
+            return Err(DummyResult::any(macro_span, guar));
         }
     };
-    match cx.source_map().load_binary_file(&file) {
-        Ok(bytes) => {
-            let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
-            base::MacEager::expr(expr)
+    match cx.source_map().load_binary_file(&resolved_path) {
+        Ok(data) => Ok(data),
+        Err(io_err) => {
+            let mut err = cx.dcx().struct_span_err(
+                macro_span,
+                format!("couldn't read `{}`: {io_err}", resolved_path.display()),
+            );
+
+            if original_path.is_relative() {
+                let source_map = cx.sess.source_map();
+                let new_path = source_map
+                    .span_to_filename(macro_span.source_callsite())
+                    .into_local_path()
+                    .and_then(|src| find_path_suggestion(source_map, src.parent()?, original_path))
+                    .and_then(|path| path.into_os_string().into_string().ok());
+
+                if let Some(new_path) = new_path {
+                    err.span_suggestion(
+                        path_span,
+                        "there is a file with the same name in a different directory",
+                        format!("\"{}\"", new_path.replace('\\', "/").escape_debug()),
+                        rustc_lint_defs::Applicability::MachineApplicable,
+                    );
+                }
+            }
+            let guar = err.emit();
+            Err(DummyResult::any(macro_span, guar))
         }
-        Err(e) => {
-            cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
-            DummyResult::any(sp)
+    }
+}
+
+fn find_path_suggestion(
+    source_map: &SourceMap,
+    base_dir: &Path,
+    wanted_path: &Path,
+) -> Option<PathBuf> {
+    // Fix paths that assume they're relative to cargo manifest dir
+    let mut base_c = base_dir.components();
+    let mut wanted_c = wanted_path.components();
+    let mut without_base = None;
+    while let Some(wanted_next) = wanted_c.next() {
+        if wanted_c.as_path().file_name().is_none() {
+            break;
+        }
+        // base_dir may be absolute
+        while let Some(base_next) = base_c.next() {
+            if base_next == wanted_next {
+                without_base = Some(wanted_c.as_path());
+                break;
+            }
         }
     }
+    let root_absolute = without_base.into_iter().map(PathBuf::from);
+
+    let base_dir_components = base_dir.components().count();
+    // Avoid going all the way to the root dir
+    let max_parent_components = if base_dir.is_relative() {
+        base_dir_components + 1
+    } else {
+        base_dir_components.saturating_sub(1)
+    };
+
+    // Try with additional leading ../
+    let mut prefix = PathBuf::new();
+    let add = std::iter::from_fn(|| {
+        prefix.push("..");
+        Some(prefix.join(wanted_path))
+    })
+    .take(max_parent_components.min(3));
+
+    // Try without leading directories
+    let mut trimmed_path = wanted_path;
+    let remove = std::iter::from_fn(|| {
+        let mut components = trimmed_path.components();
+        let removed = components.next()?;
+        trimmed_path = components.as_path();
+        let _ = trimmed_path.file_name()?; // ensure there is a file name left
+        Some([
+            Some(trimmed_path.to_path_buf()),
+            (removed != std::path::Component::ParentDir)
+                .then(|| Path::new("..").join(trimmed_path)),
+        ])
+    })
+    .flatten()
+    .flatten()
+    .take(4);
+
+    root_absolute
+        .chain(add)
+        .chain(remove)
+        .find(|new_path| source_map.file_exists(&base_dir.join(&new_path)))
 }
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 3ee3112f021..9bcd793c450 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -17,7 +17,7 @@ pub fn inject(
     features: &Features,
 ) -> usize {
     let orig_num_items = krate.items.len();
-    let edition = sess.parse_sess.edition;
+    let edition = sess.psess.edition;
 
     // the first name in this list is the crate name of the crate with the prelude
     let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) {
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 0631f796894..8f96070d149 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -5,13 +5,14 @@ use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, attr, GenericParamKind};
 use rustc_ast_pretty::pprust;
-use rustc_errors::{Applicability, DiagnosticBuilder, Level};
+use rustc_errors::{Applicability, Diag, Level};
 use rustc_expand::base::*;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{ErrorGuaranteed, FileNameDisplayPreference, Span};
 use std::assert_matches::assert_matches;
 use std::iter;
 use thin_vec::{thin_vec, ThinVec};
+use tracing::debug;
 
 /// #[test_case] is used by custom test authors to mark tests
 /// When building for test, it needs to make the item public and gensym the name
@@ -20,7 +21,7 @@ use thin_vec::{thin_vec, ThinVec};
 ///
 /// We mark item with an inert attribute "rustc_test_marker" which the test generation
 /// logic will pick up on.
-pub fn expand_test_case(
+pub(crate) fn expand_test_case(
     ecx: &mut ExtCtxt<'_>,
     attr_sp: Span,
     meta_item: &ast::MetaItem,
@@ -73,7 +74,7 @@ pub fn expand_test_case(
     vec![ret]
 }
 
-pub fn expand_test(
+pub(crate) fn expand_test(
     cx: &mut ExtCtxt<'_>,
     attr_sp: Span,
     meta_item: &ast::MetaItem,
@@ -84,7 +85,7 @@ pub fn expand_test(
     expand_test_or_bench(cx, attr_sp, item, false)
 }
 
-pub fn expand_bench(
+pub(crate) fn expand_bench(
     cx: &mut ExtCtxt<'_>,
     attr_sp: Span,
     meta_item: &ast::MetaItem,
@@ -95,8 +96,8 @@ pub fn expand_bench(
     expand_test_or_bench(cx, attr_sp, item, true)
 }
 
-pub fn expand_test_or_bench(
-    cx: &mut ExtCtxt<'_>,
+pub(crate) fn expand_test_or_bench(
+    cx: &ExtCtxt<'_>,
     attr_sp: Span,
     item: Annotatable,
     is_bench: bool,
@@ -410,7 +411,7 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
         Some(ast::ItemKind::MacCall(_)) => Level::Warning,
         _ => Level::Error,
     };
-    let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
+    let mut err = Diag::<()>::new(dcx, level, msg);
     err.span(attr_sp);
     if let Some(item) = item {
         err.span_label(
@@ -548,7 +549,7 @@ fn check_test_signature(
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let dcx = cx.dcx();
 
-    if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
+    if let ast::Safety::Unsafe(span) = f.sig.header.safety {
         return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
     }
 
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index dc28cd2ea31..38ac2f15fe7 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -9,6 +9,7 @@ use rustc_ast::{attr, ModKind};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
 use rustc_session::Session;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
@@ -159,11 +160,11 @@ struct InnerItemLinter<'a> {
 impl<'a> Visitor<'a> for InnerItemLinter<'_> {
     fn visit_item(&mut self, i: &'a ast::Item) {
         if let Some(attr) = attr::find_by_name(&i.attrs, sym::rustc_test_marker) {
-            self.sess.parse_sess.buffer_lint(
+            self.sess.psess.buffer_lint(
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
                 i.id,
-                crate::fluent_generated::builtin_macros_unnameable_test_items,
+                BuiltinLintDiag::UnnameableTestItems,
             );
         }
     }
@@ -200,7 +201,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
             EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => {
                 item.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
                     let allow_dead_code = attr::mk_attr_nested_word(
-                        &self.sess.parse_sess.attr_id_generator,
+                        &self.sess.psess.attr_id_generator,
                         ast::AttrStyle::Outer,
                         sym::allow,
                         sym::dead_code,
@@ -266,7 +267,7 @@ fn generate_test_harness(
 ///
 /// By default this expands to
 ///
-/// ```ignore UNSOLVED (I think I still need guidance for this one. Is it correct? Do we try to make it run? How do we nicely fill it out?)
+/// ```ignore (messes with test internals)
 /// #[rustc_main]
 /// pub fn main() {
 ///     extern crate test;
diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs
index e076aa6da73..4833ec32f76 100644
--- a/compiler/rustc_builtin_macros/src/trace_macros.rs
+++ b/compiler/rustc_builtin_macros/src/trace_macros.rs
@@ -1,14 +1,14 @@
 use crate::errors;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_expand::base::{self, ExtCtxt};
+use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
 use rustc_span::symbol::kw;
 use rustc_span::Span;
 
-pub fn expand_trace_macros(
+pub(crate) fn expand_trace_macros(
     cx: &mut ExtCtxt<'_>,
     sp: Span,
     tt: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
+) -> MacroExpanderResult<'static> {
     let mut cursor = tt.trees();
     let mut err = false;
     let value = match &cursor.next() {
@@ -26,5 +26,5 @@ pub fn expand_trace_macros(
         cx.set_trace_macros(value);
     }
 
-    base::DummyResult::any_valid(sp)
+    ExpandResult::Ready(DummyResult::any_valid(sp))
 }
diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs
deleted file mode 100644
index 564797012ae..00000000000
--- a/compiler/rustc_builtin_macros/src/type_ascribe.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::{token, Expr, ExprKind, Ty};
-use rustc_errors::PResult;
-use rustc_expand::base::{self, DummyResult, ExtCtxt, MacEager};
-use rustc_span::Span;
-
-pub fn expand_type_ascribe(
-    cx: &mut ExtCtxt<'_>,
-    span: Span,
-    tts: TokenStream,
-) -> Box<dyn base::MacResult + 'static> {
-    let (expr, ty) = match parse_ascribe(cx, tts) {
-        Ok(parsed) => parsed,
-        Err(err) => {
-            err.emit();
-            return DummyResult::any(span);
-        }
-    };
-
-    let asc_expr = cx.expr(span, ExprKind::Type(expr, ty));
-
-    return MacEager::expr(asc_expr);
-}
-
-fn parse_ascribe<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Expr>, P<Ty>)> {
-    let mut parser = cx.new_parser_from_tts(stream);
-
-    let expr = parser.parse_expr()?;
-    parser.expect(&token::Comma)?;
-
-    let ty = parser.parse_ty()?;
-
-    Ok((expr, ty))
-}
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index eeaf00004e6..652e34268ea 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -1,15 +1,20 @@
-use rustc_ast::{attr, AttrStyle, Attribute, MetaItem};
-use rustc_expand::base::{Annotatable, ExtCtxt};
+use crate::errors;
+use rustc_ast::tokenstream::TokenStream;
+use rustc_ast::{self as ast, attr, ptr::P, token, AttrStyle, Attribute, MetaItem};
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
+use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
+use rustc_expand::expand::AstFragment;
 use rustc_feature::AttributeTemplate;
-use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
-use rustc_parse::validate_attr;
-use rustc_span::Symbol;
+use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
+use rustc_parse::{parser, validate_attr};
+use rustc_session::errors::report_lit_error;
+use rustc_span::{BytePos, Span, Symbol};
 
-pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
+pub(crate) fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, name: Symbol) {
     // All the built-in macro attributes are "words" at the moment.
     let template = AttributeTemplate { word: true, ..Default::default() };
     validate_attr::check_builtin_meta_item(
-        &ecx.sess.parse_sess,
+        &ecx.sess.psess,
         meta_item,
         AttrStyle::Outer,
         name,
@@ -19,7 +24,7 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na
 
 /// Emit a warning if the item is annotated with the given attribute. This is used to diagnose when
 /// an attribute may have been mistakenly duplicated.
-pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
+pub(crate) fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name: Symbol) {
     let attrs: Option<&[Attribute]> = match item {
         Annotatable::Item(item) => Some(&item.attrs),
         Annotatable::TraitItem(item) => Some(&item.attrs),
@@ -37,12 +42,187 @@ pub fn warn_on_duplicate_attribute(ecx: &ExtCtxt<'_>, item: &Annotatable, name:
     };
     if let Some(attrs) = attrs {
         if let Some(attr) = attr::find_by_name(attrs, name) {
-            ecx.parse_sess().buffer_lint(
+            ecx.psess().buffer_lint(
                 DUPLICATE_MACRO_ATTRIBUTES,
                 attr.span,
                 ecx.current_expansion.lint_node_id,
-                "duplicated attribute",
+                BuiltinLintDiag::DuplicateMacroAttribute,
             );
         }
     }
 }
+
+/// `Ok` represents successfully retrieving the string literal at the correct
+/// position, e.g., `println("abc")`.
+type ExprToSpannedStringResult<'a> = Result<(Symbol, ast::StrStyle, Span), UnexpectedExprKind<'a>>;
+
+/// - `Ok` is returned when the conversion to a string literal is unsuccessful,
+/// but another type of expression is obtained instead.
+/// - `Err` is returned when the conversion process fails.
+type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), ErrorGuaranteed>;
+
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
+/// The returned bool indicates whether an applicable suggestion has already been
+/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
+/// indicates that an ast error was encountered.
+// FIXME(Nilstrieb) Make this function setup translatable
+#[allow(rustc::untranslatable_diagnostic)]
+pub(crate) fn expr_to_spanned_string<'a>(
+    cx: &'a mut ExtCtxt<'_>,
+    expr: P<ast::Expr>,
+    err_msg: &'static str,
+) -> ExpandResult<ExprToSpannedStringResult<'a>, ()> {
+    if !cx.force_mode
+        && let ast::ExprKind::MacCall(m) = &expr.kind
+        && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
+    {
+        return ExpandResult::Retry(());
+    }
+
+    // Perform eager expansion on the expression.
+    // We want to be able to handle e.g., `concat!("foo", "bar")`.
+    let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
+
+    ExpandResult::Ready(Err(match expr.kind {
+        ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
+            Ok(ast::LitKind::Str(s, style)) => {
+                return ExpandResult::Ready(Ok((s, style, expr.span)));
+            }
+            Ok(ast::LitKind::ByteStr(..)) => {
+                let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
+                let span = expr.span.shrink_to_lo();
+                err.span_suggestion(
+                    span.with_hi(span.lo() + BytePos(1)),
+                    "consider removing the leading `b`",
+                    "",
+                    Applicability::MaybeIncorrect,
+                );
+                Ok((err, true))
+            }
+            Ok(ast::LitKind::Err(guar)) => Err(guar),
+            Err(err) => Err(report_lit_error(&cx.sess.psess, err, token_lit, expr.span)),
+            _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
+        },
+        ast::ExprKind::Err(guar) => Err(guar),
+        ast::ExprKind::Dummy => {
+            cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`")
+        }
+        _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)),
+    }))
+}
+
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// emitting `err_msg` if `expr` is not a string literal. This does not stop
+/// compilation on error, merely emits a non-fatal error and returns `Err`.
+pub(crate) fn expr_to_string(
+    cx: &mut ExtCtxt<'_>,
+    expr: P<ast::Expr>,
+    err_msg: &'static str,
+) -> ExpandResult<Result<(Symbol, ast::StrStyle), ErrorGuaranteed>, ()> {
+    expr_to_spanned_string(cx, expr, err_msg).map(|res| {
+        res.map_err(|err| match err {
+            Ok((err, _)) => err.emit(),
+            Err(guar) => guar,
+        })
+        .map(|(symbol, style, _)| (symbol, style))
+    })
+}
+
+/// Non-fatally assert that `tts` is empty. Note that this function
+/// returns even when `tts` is non-empty, macros that *need* to stop
+/// compilation should call `cx.diagnostic().abort_if_errors()`
+/// (this should be done as rarely as possible).
+pub(crate) fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
+    if !tts.is_empty() {
+        cx.dcx().emit_err(errors::TakesNoArguments { span, name });
+    }
+}
+
+/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`.
+pub(crate) fn parse_expr(p: &mut parser::Parser<'_>) -> Result<P<ast::Expr>, ErrorGuaranteed> {
+    let guar = match p.parse_expr() {
+        Ok(expr) => return Ok(expr),
+        Err(err) => err.emit(),
+    };
+    while p.token != token::Eof {
+        p.bump();
+    }
+    Err(guar)
+}
+
+/// Interpreting `tts` as a comma-separated sequence of expressions,
+/// expect exactly one string literal, or emit an error and return `Err`.
+pub(crate) fn get_single_str_from_tts(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    tts: TokenStream,
+    name: &str,
+) -> ExpandResult<Result<Symbol, ErrorGuaranteed>, ()> {
+    get_single_str_spanned_from_tts(cx, span, tts, name).map(|res| res.map(|(s, _)| s))
+}
+
+pub(crate) fn get_single_str_spanned_from_tts(
+    cx: &mut ExtCtxt<'_>,
+    span: Span,
+    tts: TokenStream,
+    name: &str,
+) -> ExpandResult<Result<(Symbol, Span), ErrorGuaranteed>, ()> {
+    let mut p = cx.new_parser_from_tts(tts);
+    if p.token == token::Eof {
+        let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
+        return ExpandResult::Ready(Err(guar));
+    }
+    let ret = match parse_expr(&mut p) {
+        Ok(ret) => ret,
+        Err(guar) => return ExpandResult::Ready(Err(guar)),
+    };
+    let _ = p.eat(&token::Comma);
+
+    if p.token != token::Eof {
+        cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
+    }
+    expr_to_spanned_string(cx, ret, "argument must be a string literal").map(|res| {
+        res.map_err(|err| match err {
+            Ok((err, _)) => err.emit(),
+            Err(guar) => guar,
+        })
+        .map(|(symbol, _style, span)| (symbol, span))
+    })
+}
+
+/// Extracts comma-separated expressions from `tts`.
+/// On error, emit it, and return `Err`.
+pub(crate) fn get_exprs_from_tts(
+    cx: &mut ExtCtxt<'_>,
+    tts: TokenStream,
+) -> ExpandResult<Result<Vec<P<ast::Expr>>, ErrorGuaranteed>, ()> {
+    let mut p = cx.new_parser_from_tts(tts);
+    let mut es = Vec::new();
+    while p.token != token::Eof {
+        let expr = match parse_expr(&mut p) {
+            Ok(expr) => expr,
+            Err(guar) => return ExpandResult::Ready(Err(guar)),
+        };
+        if !cx.force_mode
+            && let ast::ExprKind::MacCall(m) = &expr.kind
+            && cx.resolver.macro_accessible(cx.current_expansion.id, &m.path).is_err()
+        {
+            return ExpandResult::Retry(());
+        }
+
+        // Perform eager expansion on the expression.
+        // We want to be able to handle e.g., `concat!("foo", "bar")`.
+        let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
+
+        es.push(expr);
+        if p.eat(&token::Comma) {
+            continue;
+        }
+        if p.token != token::Eof {
+            let guar = cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
+            return ExpandResult::Ready(Err(guar));
+        }
+    }
+    ExpandResult::Ready(Ok(es))
+}