about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-06-24 15:35:57 +0000
committerbors <bors@rust-lang.org>2025-06-24 15:35:57 +0000
commit3129d37ef7075ee3cbaa3d6cbe1b5794f67192b0 (patch)
treebe7833cbe3675fc34b9ed32748a5d9535cc0f857
parent36b21637e93b038453924d3c66821089e71d8baa (diff)
parente8dd3c356c037325bd85643f69367493a310d987 (diff)
downloadrust-3129d37ef7075ee3cbaa3d6cbe1b5794f67192b0.tar.gz
rust-3129d37ef7075ee3cbaa3d6cbe1b5794f67192b0.zip
Auto merge of #142962 - GuillaumeGomez:rollup-do1coji, r=GuillaumeGomez
Rollup of 7 pull requests

Successful merges:

 - rust-lang/rust#137268 (Allow comparisons between `CStr`, `CString`, and `Cow<CStr>`.)
 - rust-lang/rust#142704 (Remove the deprecated unstable `concat_idents!` macro)
 - rust-lang/rust#142742 ([win][aarch64] Fix linking statics on Arm64EC, take 2)
 - rust-lang/rust#142843 (Enable reproducible-build-2 for Windows MSVC)
 - rust-lang/rust#142916 (rustdoc-json: Add test for `#[optimize(..)]`)
 - rust-lang/rust#142919 (rustdoc-json: Add test for `#[cold]`)
 - rust-lang/rust#142944 (Stats output tweaks)

Failed merges:

 - rust-lang/rust#142825 (Port `#[track_caller]` to the new attribute system)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs71
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs129
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs47
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs14
-rw-r--r--compiler/rustc_interface/src/passes.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs37
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs2
-rw-r--r--compiler/rustc_passes/src/input_stats.rs61
-rw-r--r--library/alloc/src/ffi/c_str.rs109
-rw-r--r--library/core/src/ffi/c_str.rs14
-rw-r--r--library/core/src/macros/mod.rs39
-rw-r--r--library/core/src/prelude/v1.rs3
-rw-r--r--library/std/src/lib.rs6
-rw-r--r--library/std/src/prelude/v1.rs3
-rw-r--r--src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md6
-rw-r--r--src/doc/unstable-book/src/library-features/concat-idents.md27
-rw-r--r--src/tools/run-make-support/src/lib.rs2
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/tidy/src/issues.txt2
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/run-make/arm64ec-import-export-static/export.rs27
-rw-r--r--tests/run-make/arm64ec-import-export-static/import.rs12
-rw-r--r--tests/run-make/arm64ec-import-export-static/rmake.rs15
-rw-r--r--tests/run-make/reproducible-build-2/rmake.rs36
-rw-r--r--tests/run-make/sanitizer-dylib-link/program.rs2
-rw-r--r--tests/rustdoc-js/big-result.rs1
-rw-r--r--tests/rustdoc-json/attrs/cold.rs3
-rw-r--r--tests/rustdoc-json/attrs/optimize.rs13
-rw-r--r--tests/ui/derives/nonsense-input-to-debug.rs12
-rw-r--r--tests/ui/derives/nonsense-input-to-debug.stderr30
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents.rs11
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents.stderr23
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents2.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents2.stderr20
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents3.rs9
-rw-r--r--tests/ui/feature-gates/feature-gate-concat_idents3.stderr23
-rw-r--r--tests/ui/issues/issue-32950.rs10
-rw-r--r--tests/ui/issues/issue-32950.stderr15
-rw-r--r--tests/ui/issues/issue-50403.rs6
-rw-r--r--tests/ui/issues/issue-50403.stderr8
-rw-r--r--tests/ui/macros/macro-comma-support-rpass.rs12
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/empty-input.rs12
-rw-r--r--tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr19
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.rs5
-rw-r--r--tests/ui/macros/macros-nonfatal-errors.stderr68
-rw-r--r--tests/ui/stats/input-stats.stderr196
-rw-r--r--tests/ui/syntax-extension-minor.rs15
-rw-r--r--tests/ui/unpretty/exhaustive.expanded.stdout10
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stderr40
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stdout10
-rw-r--r--tests/ui/unpretty/exhaustive.rs11
56 files changed, 700 insertions, 603 deletions
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index c5d1f2ad2de..3594c7ec210 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -118,10 +118,6 @@ builtin_macros_concat_bytes_oob = numeric literal is out of bounds
 builtin_macros_concat_bytestr = cannot concatenate a byte string literal
 builtin_macros_concat_c_str_lit = cannot concatenate a C string literal
 
-builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
-
-builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
-builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
 builtin_macros_concat_missing_literal = expected a literal
     .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
 
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
deleted file mode 100644
index a721f5b84c5..00000000000
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
-use rustc_ast::tokenstream::{TokenStream, TokenTree};
-use rustc_ast::{AttrVec, DUMMY_NODE_ID, Expr, ExprKind, Path, Ty, TyKind};
-use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
-use rustc_span::{Ident, Span, Symbol};
-
-use crate::errors;
-
-pub(crate) fn expand_concat_idents<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> MacroExpanderResult<'cx> {
-    if tts.is_empty() {
-        let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
-        return ExpandResult::Ready(DummyResult::any(sp, guar));
-    }
-
-    let mut res_str = String::new();
-    for (i, e) in tts.iter().enumerate() {
-        if i & 1 == 1 {
-            match e {
-                TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
-                _ => {
-                    let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
-                    return ExpandResult::Ready(DummyResult::any(sp, guar));
-                }
-            }
-        } else {
-            if let TokenTree::Token(token, _) = e {
-                if let Some((ident, _)) = token.ident() {
-                    res_str.push_str(ident.name.as_str());
-                    continue;
-                }
-            }
-
-            let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
-            return ExpandResult::Ready(DummyResult::any(sp, guar));
-        }
-    }
-
-    let ident = Ident::new(Symbol::intern(&res_str), cx.with_call_site_ctxt(sp));
-
-    struct ConcatIdentsResult {
-        ident: 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: AttrVec::new(),
-                tokens: None,
-            }))
-        }
-
-        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,
-            }))
-        }
-    }
-
-    ExpandResult::Ready(Box::new(ConcatIdentsResult { ident }))
-}
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index b7ecfd2285c..fe34cf5d6fa 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -300,27 +300,6 @@ pub(crate) struct ConcatBytesBadRepeat {
 }
 
 #[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_missing_args)]
-pub(crate) struct ConcatIdentsMissingArgs {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_missing_comma)]
-pub(crate) struct ConcatIdentsMissingComma {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(builtin_macros_concat_idents_ident_args)]
-pub(crate) struct ConcatIdentsIdentArgs {
-    #[primary_span]
-    pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(builtin_macros_bad_derive_target, code = E0774)]
 pub(crate) struct BadDeriveTarget {
     #[primary_span]
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 9e7d0ec9e81..9b6dea21438 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -36,7 +36,6 @@ mod cfg_eval;
 mod compile_error;
 mod concat;
 mod concat_bytes;
-mod concat_idents;
 mod define_opaque;
 mod derive;
 mod deriving;
@@ -84,7 +83,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         compile_error: compile_error::expand_compile_error,
         concat: concat::expand_concat,
         concat_bytes: concat_bytes::expand_concat_bytes,
-        concat_idents: concat_idents::expand_concat_idents,
         const_format_args: format::expand_format_args,
         core_panic: edition_panic::expand_panic,
         env: env::expand_env,
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 8fc83908efb..b6892bb63e8 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -337,7 +337,12 @@ pub(crate) trait Linker {
     fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
     fn no_crt_objects(&mut self);
     fn no_default_libraries(&mut self);
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    );
     fn subsystem(&mut self, subsystem: &str);
     fn linker_plugin_lto(&mut self);
     fn add_eh_frame_header(&mut self) {}
@@ -770,7 +775,12 @@ impl<'a> Linker for GccLinker<'a> {
         }
     }
 
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         // Symbol visibility in object files typically takes care of this.
         if crate_type == CrateType::Executable {
             let should_export_executable_symbols =
@@ -799,7 +809,7 @@ impl<'a> Linker for GccLinker<'a> {
             // Write a plain, newline-separated list of symbols
             let res: io::Result<()> = try {
                 let mut f = File::create_buffered(&path)?;
-                for sym in symbols {
+                for (sym, _) in symbols {
                     debug!("  _{sym}");
                     writeln!(f, "_{sym}")?;
                 }
@@ -814,11 +824,12 @@ impl<'a> Linker for GccLinker<'a> {
                 // .def file similar to MSVC one but without LIBRARY section
                 // because LD doesn't like when it's empty
                 writeln!(f, "EXPORTS")?;
-                for symbol in symbols {
+                for (symbol, kind) in symbols {
+                    let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
                     debug!("  _{symbol}");
                     // Quote the name in case it's reserved by linker in some way
                     // (this accounts for names with dots in particular).
-                    writeln!(f, "  \"{symbol}\"")?;
+                    writeln!(f, "  \"{symbol}\"{kind_marker}")?;
                 }
             };
             if let Err(error) = res {
@@ -831,7 +842,7 @@ impl<'a> Linker for GccLinker<'a> {
                 writeln!(f, "{{")?;
                 if !symbols.is_empty() {
                     writeln!(f, "  global:")?;
-                    for sym in symbols {
+                    for (sym, _) in symbols {
                         debug!("    {sym};");
                         writeln!(f, "    {sym};")?;
                     }
@@ -1098,7 +1109,12 @@ impl<'a> Linker for MsvcLinker<'a> {
     // crates. Upstream rlibs may be linked statically to this dynamic library,
     // in which case they may continue to transitively be used and hence need
     // their symbols exported.
-    fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         // Symbol visibility takes care of this typically
         if crate_type == CrateType::Executable {
             let should_export_executable_symbols =
@@ -1116,9 +1132,10 @@ impl<'a> Linker for MsvcLinker<'a> {
             // straight to exports.
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
-            for symbol in symbols {
+            for (symbol, kind) in symbols {
+                let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
                 debug!("  _{symbol}");
-                writeln!(f, "  {symbol}")?;
+                writeln!(f, "  {symbol}{kind_marker}")?;
             }
         };
         if let Err(error) = res {
@@ -1259,14 +1276,19 @@ impl<'a> Linker for EmLinker<'a> {
         self.cc_arg("-nodefaultlibs");
     }
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         debug!("EXPORTED SYMBOLS:");
 
         self.cc_arg("-s");
 
         let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
         let encoded = serde_json::to_string(
-            &symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
+            &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
         )
         .unwrap();
         debug!("{encoded}");
@@ -1428,8 +1450,13 @@ impl<'a> Linker for WasmLd<'a> {
 
     fn no_default_libraries(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
-        for sym in symbols {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
+        for (sym, _) in symbols {
             self.link_args(&["--export", sym]);
         }
 
@@ -1563,7 +1590,7 @@ impl<'a> Linker for L4Bender<'a> {
         self.cc_arg("-nostdlib");
     }
 
-    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
+    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
         // ToDo, not implemented, copy from GCC
         self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
     }
@@ -1720,12 +1747,17 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn no_default_libraries(&mut self) {}
 
-    fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         let path = tmpdir.join("list.exp");
         let res: io::Result<()> = try {
             let mut f = File::create_buffered(&path)?;
             // FIXME: use llvm-nm to generate export list.
-            for symbol in symbols {
+            for (symbol, _) in symbols {
                 debug!("  _{symbol}");
                 writeln!(f, "  {symbol}")?;
             }
@@ -1769,9 +1801,23 @@ fn for_each_exported_symbols_include_dep<'tcx>(
     }
 }
 
-pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+pub(crate) fn exported_symbols(
+    tcx: TyCtxt<'_>,
+    crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
-        return exports.iter().map(ToString::to_string).collect();
+        return exports
+            .iter()
+            .map(|name| {
+                (
+                    name.to_string(),
+                    // FIXME use the correct export kind for this symbol. override_export_symbols
+                    // can't directly specify the SymbolExportKind as it is defined in rustc_middle
+                    // which rustc_target can't depend on.
+                    SymbolExportKind::Text,
+                )
+            })
+            .collect();
     }
 
     if let CrateType::ProcMacro = crate_type {
@@ -1781,7 +1827,10 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
     }
 }
 
-fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
+fn exported_symbols_for_non_proc_macro(
+    tcx: TyCtxt<'_>,
+    crate_type: CrateType,
+) -> Vec<(String, SymbolExportKind)> {
     let mut symbols = Vec::new();
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
     for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
@@ -1789,8 +1838,9 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
         // from any cdylib. The latter doesn't work anyway as we use hidden visibility for
         // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
         if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
-            symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
-                tcx, symbol, cnum,
+            symbols.push((
+                symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                info.kind,
             ));
             symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
         }
@@ -1799,7 +1849,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
     symbols
 }
 
-fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
+fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
     // `exported_symbols` will be empty when !should_codegen.
     if !tcx.sess.opts.output_types.should_codegen() {
         return Vec::new();
@@ -1809,7 +1859,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
     let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
     let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
 
-    vec![proc_macro_decls_name, metadata_symbol_name]
+    vec![
+        (proc_macro_decls_name, SymbolExportKind::Data),
+        (metadata_symbol_name, SymbolExportKind::Data),
+    ]
 }
 
 pub(crate) fn linked_symbols(
@@ -1831,7 +1884,9 @@ pub(crate) fn linked_symbols(
             || info.used
         {
             symbols.push((
-                symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
+                symbol_export::linking_symbol_name_for_instance_in_crate(
+                    tcx, symbol, info.kind, cnum,
+                ),
                 info.kind,
             ));
         }
@@ -1906,7 +1961,13 @@ impl<'a> Linker for PtxLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        _symbols: &[(String, SymbolExportKind)],
+    ) {
+    }
 
     fn subsystem(&mut self, _subsystem: &str) {}
 
@@ -1975,10 +2036,15 @@ impl<'a> Linker for LlbcLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        _tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         match _crate_type {
             CrateType::Cdylib => {
-                for sym in symbols {
+                for (sym, _) in symbols {
                     self.link_args(&["--export-symbol", sym]);
                 }
             }
@@ -2052,11 +2118,16 @@ impl<'a> Linker for BpfLinker<'a> {
 
     fn ehcont_guard(&mut self) {}
 
-    fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
+    fn export_symbols(
+        &mut self,
+        tmpdir: &Path,
+        _crate_type: CrateType,
+        symbols: &[(String, SymbolExportKind)],
+    ) {
         let path = tmpdir.join("symbols");
         let res: io::Result<()> = try {
             let mut f = File::create_buffered(&path)?;
-            for sym in symbols {
+            for (sym, _) in symbols {
                 writeln!(f, "{sym}")?;
             }
         };
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index d0b6c7470fb..19c005d418e 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -680,6 +680,7 @@ fn calling_convention_for_symbol<'tcx>(
 pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
     tcx: TyCtxt<'tcx>,
     symbol: ExportedSymbol<'tcx>,
+    export_kind: SymbolExportKind,
     instantiating_crate: CrateNum,
 ) -> String {
     let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
@@ -700,8 +701,9 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
     let prefix = match &target.arch[..] {
         "x86" => Some('_'),
         "x86_64" => None,
-        "arm64ec" => Some('#'),
-        // Only x86/64 use symbol decorations.
+        // Only functions are decorated for arm64ec.
+        "arm64ec" if export_kind == SymbolExportKind::Text => Some('#'),
+        // Only x86/64 and arm64ec use symbol decorations.
         _ => return undecorated,
     };
 
@@ -741,7 +743,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
 /// Add it to the symbols list for all kernel functions, so that it is exported in the linked
 /// object.
 pub(crate) fn extend_exported_symbols<'tcx>(
-    symbols: &mut Vec<String>,
+    symbols: &mut Vec<(String, SymbolExportKind)>,
     tcx: TyCtxt<'tcx>,
     symbol: ExportedSymbol<'tcx>,
     instantiating_crate: CrateNum,
@@ -755,7 +757,9 @@ pub(crate) fn extend_exported_symbols<'tcx>(
     let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
 
     // Add the symbol for the kernel descriptor (with .kd suffix)
-    symbols.push(format!("{undecorated}.kd"));
+    // Per https://llvm.org/docs/AMDGPUUsage.html#symbols these will always be `STT_OBJECT` so
+    // export as data.
+    symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data));
 }
 
 fn maybe_emutls_symbol_name<'tcx>(
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index a3d6c73ba85..cc90271cd0c 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -12,9 +12,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
 use rustc_data_structures::unord::UnordMap;
-use rustc_hir::ItemId;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::lang_items::LangItem;
+use rustc_hir::{ItemId, Target};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
 use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
 use rustc_middle::middle::exported_symbols::{self, SymbolExportKind};
@@ -1003,21 +1003,35 @@ impl CrateInfo {
         // by the compiler, but that's ok because all this stuff is unstable anyway.
         let target = &tcx.sess.target;
         if !are_upstream_rust_objects_already_included(tcx.sess) {
-            let missing_weak_lang_items: FxIndexSet<Symbol> = info
+            let add_prefix = match (target.is_like_windows, target.arch.as_ref()) {
+                (true, "x86") => |name: String, _: SymbolExportKind| format!("_{name}"),
+                (true, "arm64ec") => {
+                    // Only functions are decorated for arm64ec.
+                    |name: String, export_kind: SymbolExportKind| match export_kind {
+                        SymbolExportKind::Text => format!("#{name}"),
+                        _ => name,
+                    }
+                }
+                _ => |name: String, _: SymbolExportKind| name,
+            };
+            let missing_weak_lang_items: FxIndexSet<(Symbol, SymbolExportKind)> = info
                 .used_crates
                 .iter()
                 .flat_map(|&cnum| tcx.missing_lang_items(cnum))
                 .filter(|l| l.is_weak())
                 .filter_map(|&l| {
                     let name = l.link_name()?;
-                    lang_items::required(tcx, l).then_some(name)
+                    let export_kind = match l.target() {
+                        Target::Fn => SymbolExportKind::Text,
+                        Target::Static => SymbolExportKind::Data,
+                        _ => bug!(
+                            "Don't know what the export kind is for lang item of kind {:?}",
+                            l.target()
+                        ),
+                    };
+                    lang_items::required(tcx, l).then_some((name, export_kind))
                 })
                 .collect();
-            let prefix = match (target.is_like_windows, target.arch.as_ref()) {
-                (true, "x86") => "_",
-                (true, "arm64ec") => "#",
-                _ => "",
-            };
 
             // This loop only adds new items to values of the hash map, so the order in which we
             // iterate over the values is not important.
@@ -1030,10 +1044,13 @@ impl CrateInfo {
                 .for_each(|(_, linked_symbols)| {
                     let mut symbols = missing_weak_lang_items
                         .iter()
-                        .map(|item| {
+                        .map(|(item, export_kind)| {
                             (
-                                format!("{prefix}{}", mangle_internal_symbol(tcx, item.as_str())),
-                                SymbolExportKind::Text,
+                                add_prefix(
+                                    mangle_internal_symbol(tcx, item.as_str()),
+                                    *export_kind,
+                                ),
+                                *export_kind,
                             )
                         })
                         .collect::<Vec<_>>();
@@ -1048,12 +1065,12 @@ impl CrateInfo {
                         // errors.
                         linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
                             (
-                                format!(
-                                    "{prefix}{}",
+                                add_prefix(
                                     mangle_internal_symbol(
                                         tcx,
-                                        global_fn_name(method.name).as_str()
-                                    )
+                                        global_fn_name(method.name).as_str(),
+                                    ),
+                                    SymbolExportKind::Text,
                                 ),
                                 SymbolExportKind::Text,
                             )
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 523c9f2ad1c..23ed387a3ff 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -218,7 +218,7 @@ pub struct CrateInfo {
     pub target_cpu: String,
     pub target_features: Vec<String>,
     pub crate_types: Vec<CrateType>,
-    pub exported_symbols: UnordMap<CrateType, Vec<String>>,
+    pub exported_symbols: UnordMap<CrateType, Vec<(String, SymbolExportKind)>>,
     pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>,
     pub local_crate_name: Symbol,
     pub compiler_builtins: Option<CrateNum>,
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 0cd090b25a4..c54b831e244 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -285,4 +285,18 @@ declare_features! (
     // -------------------------------------------------------------------------
     // feature-group-end: removed features
     // -------------------------------------------------------------------------
+
+
+    // -------------------------------------------------------------------------
+    // feature-group-start: removed library features
+    // -------------------------------------------------------------------------
+    //
+    // FIXME(#141617): we should have a better way to track removed library features, but we reuse
+    // the infrastructure here so users still get hints. The symbols used here can be remove from
+    // `symbol.rs` when that happens.
+    (removed, concat_idents, "CURRENT_RUSTC_VERSION", Some(29599),
+     Some("use the `${concat(..)}` metavariable expression instead"), 142704),
+    // -------------------------------------------------------------------------
+    // feature-group-end: removed library features
+    // -------------------------------------------------------------------------
 );
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 0b9facfc7af..e8c23ef997c 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -371,7 +371,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let mut lint_buffer = resolver.lint_buffer.steal();
 
     if sess.opts.unstable_opts.input_stats {
-        input_stats::print_ast_stats(krate, "POST EXPANSION AST STATS", "ast-stats");
+        input_stats::print_ast_stats(tcx, krate);
     }
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 00bd32eb0eb..ed3c18a02a6 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -762,6 +762,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         assert_eq!(total_bytes, computed_total_bytes);
 
         if tcx.sess.opts.unstable_opts.meta_stats {
+            use std::fmt::Write;
+
             self.opaque.flush();
 
             // Rewind and re-read all the metadata to count the zero bytes we wrote.
@@ -777,31 +779,44 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             assert_eq!(self.opaque.file().stream_position().unwrap(), pos_before_rewind);
 
             stats.sort_by_key(|&(_, usize)| usize);
+            stats.reverse(); // bigger items first
 
             let prefix = "meta-stats";
             let perc = |bytes| (bytes * 100) as f64 / total_bytes as f64;
 
-            eprintln!("{prefix} METADATA STATS");
-            eprintln!("{} {:<23}{:>10}", prefix, "Section", "Size");
-            eprintln!("{prefix} ----------------------------------------------------------------");
+            let section_w = 23;
+            let size_w = 10;
+            let banner_w = 64;
+
+            // We write all the text into a string and print it with a single
+            // `eprint!`. This is an attempt to minimize interleaved text if multiple
+            // rustc processes are printing macro-stats at the same time (e.g. with
+            // `RUSTFLAGS='-Zmeta-stats' cargo build`). It still doesn't guarantee
+            // non-interleaving, though.
+            let mut s = String::new();
+            _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+            _ = writeln!(s, "{prefix} METADATA STATS: {}", tcx.crate_name(LOCAL_CRATE));
+            _ = writeln!(s, "{prefix} {:<section_w$}{:>size_w$}", "Section", "Size");
+            _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
             for (label, size) in stats {
-                eprintln!(
-                    "{} {:<23}{:>10} ({:4.1}%)",
-                    prefix,
+                _ = writeln!(
+                    s,
+                    "{prefix} {:<section_w$}{:>size_w$} ({:4.1}%)",
                     label,
                     usize_with_underscores(size),
                     perc(size)
                 );
             }
-            eprintln!("{prefix} ----------------------------------------------------------------");
-            eprintln!(
-                "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
-                prefix,
+            _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
+            _ = writeln!(
+                s,
+                "{prefix} {:<section_w$}{:>size_w$} (of which {:.1}% are zero bytes)",
                 "Total",
                 usize_with_underscores(total_bytes),
                 perc(zero_bytes)
             );
-            eprintln!("{prefix}");
+            _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+            eprint!("{s}");
         }
 
         root
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index 1d67d0fe3bb..64a1f2aff15 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -22,7 +22,7 @@ impl SymbolExportLevel {
 }
 
 /// Kind of exported symbols.
-#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, Encodable, Decodable, HashStable, Hash)]
 pub enum SymbolExportKind {
     Text,
     Data,
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 46e6c0bf7da..40bc18939d6 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -65,16 +65,16 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
         StatCollector { tcx: Some(tcx), nodes: FxHashMap::default(), seen: FxHashSet::default() };
     tcx.hir_walk_toplevel_module(&mut collector);
     tcx.hir_walk_attributes(&mut collector);
-    collector.print("HIR STATS", "hir-stats");
+    collector.print(tcx, "HIR STATS", "hir-stats");
 }
 
-pub fn print_ast_stats(krate: &ast::Crate, title: &str, prefix: &str) {
+pub fn print_ast_stats(tcx: TyCtxt<'_>, krate: &ast::Crate) {
     use rustc_ast::visit::Visitor;
 
     let mut collector =
         StatCollector { tcx: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
     collector.visit_crate(krate);
-    collector.print(title, prefix);
+    collector.print(tcx, "POST EXPANSION AST STATS", "ast-stats");
 }
 
 impl<'k> StatCollector<'k> {
@@ -116,29 +116,48 @@ impl<'k> StatCollector<'k> {
         }
     }
 
-    fn print(&self, title: &str, prefix: &str) {
+    fn print(&self, tcx: TyCtxt<'_>, title: &str, prefix: &str) {
+        use std::fmt::Write;
+
         // We will soon sort, so the initial order does not matter.
         #[allow(rustc::potential_query_instability)]
         let mut nodes: Vec<_> = self.nodes.iter().collect();
         nodes.sort_by_cached_key(|(label, node)| (node.stats.accum_size(), label.to_owned()));
+        nodes.reverse(); // bigger items first
+
+        let name_w = 18;
+        let acc_size1_w = 10;
+        let acc_size2_w = 8; // " (NN.N%)"
+        let acc_size_w = acc_size1_w + acc_size2_w;
+        let count_w = 14;
+        let item_size_w = 14;
+        let banner_w = name_w + acc_size_w + count_w + item_size_w;
 
         let total_size = nodes.iter().map(|(_, node)| node.stats.accum_size()).sum();
         let total_count = nodes.iter().map(|(_, node)| node.stats.count).sum();
 
-        eprintln!("{prefix} {title}");
-        eprintln!(
-            "{} {:<18}{:>18}{:>14}{:>14}",
-            prefix, "Name", "Accumulated Size", "Count", "Item Size"
+        // We write all the text into a string and print it with a single
+        // `eprint!`. This is an attempt to minimize interleaved text if multiple
+        // rustc processes are printing macro-stats at the same time (e.g. with
+        // `RUSTFLAGS='-Zinput-stats' cargo build`). It still doesn't guarantee
+        // non-interleaving, though.
+        let mut s = String::new();
+        _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+        _ = writeln!(s, "{prefix} {title}: {}", tcx.crate_name(hir::def_id::LOCAL_CRATE));
+        _ = writeln!(
+            s,
+            "{prefix} {:<name_w$}{:>acc_size_w$}{:>count_w$}{:>item_size_w$}",
+            "Name", "Accumulated Size", "Count", "Item Size"
         );
-        eprintln!("{prefix} ----------------------------------------------------------------");
+        _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
 
         let percent = |m, n| (m * 100) as f64 / n as f64;
 
         for (label, node) in nodes {
             let size = node.stats.accum_size();
-            eprintln!(
-                "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
-                prefix,
+            _ = writeln!(
+                s,
+                "{prefix} {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}{:>item_size_w$}",
                 label,
                 usize_with_underscores(size),
                 percent(size, total_size),
@@ -155,9 +174,9 @@ impl<'k> StatCollector<'k> {
 
                 for (label, subnode) in subnodes {
                     let size = subnode.accum_size();
-                    eprintln!(
-                        "{} - {:<18}{:>10} ({:4.1}%){:>14}",
-                        prefix,
+                    _ = writeln!(
+                        s,
+                        "{prefix} - {:<name_w$}{:>acc_size1_w$} ({:4.1}%){:>count_w$}",
                         label,
                         usize_with_underscores(size),
                         percent(size, total_size),
@@ -166,15 +185,17 @@ impl<'k> StatCollector<'k> {
                 }
             }
         }
-        eprintln!("{prefix} ----------------------------------------------------------------");
-        eprintln!(
-            "{} {:<18}{:>10}        {:>14}",
-            prefix,
+        _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
+        _ = writeln!(
+            s,
+            "{prefix} {:<name_w$}{:>acc_size1_w$}{:>acc_size2_w$}{:>count_w$}",
             "Total",
             usize_with_underscores(total_size),
+            "",
             usize_with_underscores(total_count),
         );
-        eprintln!("{prefix}");
+        _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+        eprint!("{s}");
     }
 }
 
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 48849bf7536..93bdad75380 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -1099,6 +1099,46 @@ impl From<&CStr> for CString {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CStr> for CString {
+    #[inline]
+    fn eq(&self, other: &CStr) -> bool {
+        **self == *other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CStr) -> bool {
+        **self != *other
+    }
+}
+
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&CStr> for CString {
+    #[inline]
+    fn eq(&self, other: &&CStr) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&CStr) -> bool {
+        **self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<Cow<'_, CStr>> for CString {
+    #[inline]
+    fn eq(&self, other: &Cow<'_, CStr>) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &Cow<'_, CStr>) -> bool {
+        **self != **other
+    }
+}
+
 #[stable(feature = "cstring_asref", since = "1.7.0")]
 impl ops::Index<ops::RangeFull> for CString {
     type Output = CStr;
@@ -1181,6 +1221,75 @@ impl CStr {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CString> for CStr {
+    #[inline]
+    fn eq(&self, other: &CString) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CString) -> bool {
+        *self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<Cow<'_, Self>> for CStr {
+    #[inline]
+    fn eq(&self, other: &Cow<'_, Self>) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &Cow<'_, Self>) -> bool {
+        *self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CStr> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &CStr) -> bool {
+        **self == *other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CStr) -> bool {
+        **self != *other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&CStr> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &&CStr) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&CStr) -> bool {
+        **self != **other
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<CString> for Cow<'_, CStr> {
+    #[inline]
+    fn eq(&self, other: &CString) -> bool {
+        **self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &CString) -> bool {
+        **self != **other
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl core::error::Error for NulError {
     #[allow(deprecated)]
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index f7a21072f53..1d2e13db218 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -660,6 +660,19 @@ impl CStr {
     }
 }
 
+#[stable(feature = "c_string_eq_c_str", since = "CURRENT_RUSTC_VERSION")]
+impl PartialEq<&Self> for CStr {
+    #[inline]
+    fn eq(&self, other: &&Self) -> bool {
+        *self == **other
+    }
+
+    #[inline]
+    fn ne(&self, other: &&Self) -> bool {
+        *self != **other
+    }
+}
+
 // `.to_bytes()` representations are compared instead of the inner `[c_char]`s,
 // because `c_char` is `i8` (not `u8`) on some platforms.
 // That is why this is implemented manually and not derived.
@@ -670,6 +683,7 @@ impl PartialOrd for CStr {
         self.to_bytes().partial_cmp(&other.to_bytes())
     }
 }
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl Ord for CStr {
     #[inline]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index d7b2ec81555..8035dccc632 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1109,45 +1109,6 @@ pub(crate) mod builtin {
         ($name:expr $(,)?) => {{ /* compiler built-in */ }};
     }
 
-    /// Concatenates identifiers into one identifier.
-    ///
-    /// This macro takes any number of comma-separated identifiers, and
-    /// concatenates them all into one, yielding an expression which is a new
-    /// identifier. Note that hygiene makes it such that this macro cannot
-    /// capture local variables. Also, as a general rule, macros are only
-    /// allowed in item, statement or expression position. That means while
-    /// you may use this macro for referring to existing variables, functions or
-    /// modules etc, you cannot define a new one with it.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(concat_idents)]
-    ///
-    /// # fn main() {
-    /// fn foobar() -> u32 { 23 }
-    ///
-    /// let f = concat_idents!(foo, bar);
-    /// println!("{}", f());
-    ///
-    /// // fn concat_idents!(new, fun, name) { } // not usable in this way!
-    /// # }
-    /// ```
-    #[unstable(
-        feature = "concat_idents",
-        issue = "29599",
-        reason = "`concat_idents` is not stable enough for use and is subject to change"
-    )]
-    #[deprecated(
-        since = "1.88.0",
-        note = "use `${concat(...)}` with the `macro_metavar_expr_concat` feature instead"
-    )]
-    #[rustc_builtin_macro]
-    #[macro_export]
-    macro_rules! concat_idents {
-        ($($e:ident),+ $(,)?) => {{ /* compiler built-in */ }};
-    }
-
     /// Concatenates literals into a byte slice.
     ///
     /// This macro takes any number of comma-separated literals, and concatenates them all into
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index 8f1b5275871..7b9e04920d5 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -58,10 +58,9 @@ pub use crate::fmt::macros::Debug;
 pub use crate::hash::macros::Hash;
 
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 #[doc(no_inline)]
 pub use crate::{
-    assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
+    assert, cfg, column, compile_error, concat, env, file, format_args,
     format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
     stringify, trace_macros,
 };
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 2bb7a63772d..13fb08a9210 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -281,7 +281,6 @@
 #![feature(cfg_target_thread_local)]
 #![feature(cfi_encoding)]
 #![feature(char_max_len)]
-#![feature(concat_idents)]
 #![feature(core_float_math)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
@@ -717,10 +716,9 @@ pub use core::primitive;
 pub use core::todo;
 // Re-export built-in macros defined through core.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 pub use core::{
-    assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
-    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
+    assert, assert_matches, cfg, column, compile_error, concat, const_format_args, env, file,
+    format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
     module_path, option_env, stringify, trace_macros,
 };
 // Re-export macros defined in core.
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index c15d8c40085..69f03353153 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -45,10 +45,9 @@ pub use crate::result::Result::{self, Err, Ok};
 
 // Re-exported built-in macros
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated)]
 #[doc(no_inline)]
 pub use core::prelude::v1::{
-    assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
+    assert, cfg, column, compile_error, concat, env, file, format_args,
     format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
     stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
 };
diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
index b6dbdb14407..7eb5dca532f 100644
--- a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
+++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
@@ -8,7 +8,8 @@ In stable Rust, there is no way to create new identifiers by joining identifiers
  `#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression.
 
 > This feature uses the syntax from [`macro_metavar_expr`] but is otherwise
-> independent. It replaces the old unstable feature [`concat_idents`].
+> independent. It replaces the since-removed unstable feature
+> [`concat_idents`].
 
 > This is an experimental feature; it and its syntax will require a RFC before stabilization.
 
@@ -126,8 +127,7 @@ test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; fini
 
 [`paste`]: https://crates.io/crates/paste
 [RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
-[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html
 [`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md
-[`concat_idents`]: ../library-features/concat-idents.md
+[`concat_idents`]: https://github.com/rust-lang/rust/issues/29599
 [#124225]: https://github.com/rust-lang/rust/issues/124225
 [declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html
diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md
deleted file mode 100644
index 8a38d155e3d..00000000000
--- a/src/doc/unstable-book/src/library-features/concat-idents.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# `concat_idents`
-
-The tracking issue for this feature is: [#29599]
-
-This feature is deprecated, to be replaced by [`macro_metavar_expr_concat`].
-
-[#29599]: https://github.com/rust-lang/rust/issues/29599
-[`macro_metavar_expr_concat`]: https://github.com/rust-lang/rust/issues/124225
-
-------------------------
-
-> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md).
-
-The `concat_idents` feature adds a macro for concatenating multiple identifiers
-into one identifier.
-
-## Examples
-
-```rust
-#![feature(concat_idents)]
-
-fn main() {
-    fn foobar() -> u32 { 23 }
-    let f = concat_idents!(foo, bar);
-    assert_eq!(f(), 23);
-}
-```
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 947f815fd69..67d8c351a59 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -83,7 +83,7 @@ pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
 pub use targets::{
-    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_win7, llvm_components_contain,
+    apple_os, is_aix, is_darwin, is_msvc, is_windows, is_windows_gnu, is_windows_msvc, is_win7, llvm_components_contain,
     target, uname,
 };
 
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index 86edbdf750b..1ab2e2ab2be 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -28,6 +28,12 @@ pub fn is_windows_gnu() -> bool {
     target().ends_with("windows-gnu")
 }
 
+/// Check if target is windows-msvc.
+#[must_use]
+pub fn is_windows_msvc() -> bool {
+    target().ends_with("windows-msvc")
+}
+
 /// Check if target is win7.
 #[must_use]
 pub fn is_win7() -> bool {
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index b3517b2e9da..24356c31da4 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2070,7 +2070,6 @@ ui/issues/issue-32782.rs
 ui/issues/issue-32797.rs
 ui/issues/issue-32805.rs
 ui/issues/issue-3290.rs
-ui/issues/issue-32950.rs
 ui/issues/issue-32995-2.rs
 ui/issues/issue-32995.rs
 ui/issues/issue-33202.rs
@@ -2340,7 +2339,6 @@ ui/issues/issue-49934.rs
 ui/issues/issue-49955.rs
 ui/issues/issue-49973.rs
 ui/issues/issue-50187.rs
-ui/issues/issue-50403.rs
 ui/issues/issue-50411.rs
 ui/issues/issue-50415.rs
 ui/issues/issue-50442.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 8f9b07c49ac..53226fcb80e 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@ use ignore::Walk;
 const ENTRY_LIMIT: u32 = 901;
 // FIXME: The following limits should be reduced eventually.
 
-const ISSUES_ENTRY_LIMIT: u32 = 1623;
+const ISSUES_ENTRY_LIMIT: u32 = 1619;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/run-make/arm64ec-import-export-static/export.rs b/tests/run-make/arm64ec-import-export-static/export.rs
new file mode 100644
index 00000000000..ca6ccf00ca1
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/export.rs
@@ -0,0 +1,27 @@
+#![crate_type = "dylib"]
+#![allow(internal_features)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![no_std]
+
+// This is needed because of #![no_core]:
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+#[lang = "sync"]
+trait Sync {}
+impl Sync for i32 {}
+#[lang = "copy"]
+pub trait Copy {}
+impl Copy for i32 {}
+#[lang = "drop_in_place"]
+pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
+#[no_mangle]
+extern "system" fn _DllMainCRTStartup(_: *const u8, _: u32, _: *const u8) -> u32 {
+    1
+}
+
+pub static VALUE: i32 = 42;
diff --git a/tests/run-make/arm64ec-import-export-static/import.rs b/tests/run-make/arm64ec-import-export-static/import.rs
new file mode 100644
index 00000000000..9d52db25125
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/import.rs
@@ -0,0 +1,12 @@
+#![crate_type = "cdylib"]
+#![allow(internal_features)]
+#![feature(no_core)]
+#![no_std]
+#![no_core]
+
+extern crate export;
+
+#[no_mangle]
+pub extern "C" fn func() -> i32 {
+    export::VALUE
+}
diff --git a/tests/run-make/arm64ec-import-export-static/rmake.rs b/tests/run-make/arm64ec-import-export-static/rmake.rs
new file mode 100644
index 00000000000..7fa31144810
--- /dev/null
+++ b/tests/run-make/arm64ec-import-export-static/rmake.rs
@@ -0,0 +1,15 @@
+// Test that a static can be exported from one crate and imported into another.
+//
+// This was broken for Arm64EC as only functions, not variables, should be
+// decorated with `#`.
+// See https://github.com/rust-lang/rust/issues/138541
+
+//@ needs-llvm-components: aarch64
+//@ only-windows
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc().input("export.rs").target("aarch64-pc-windows-msvc").panic("abort").run();
+    rustc().input("import.rs").target("aarch64-pc-windows-msvc").panic("abort").run();
+}
diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs
index 5971fa01f92..1de5ca1e6f7 100644
--- a/tests/run-make/reproducible-build-2/rmake.rs
+++ b/tests/run-make/reproducible-build-2/rmake.rs
@@ -7,22 +7,36 @@
 // See https://github.com/rust-lang/rust/issues/34902
 
 //@ ignore-cross-compile
-//@ ignore-windows
-// Reasons:
-// 1. The object files are reproducible, but their paths are not, which causes
-// the first assertion in the test to fail.
-// 2. When the sysroot gets copied, some symlinks must be re-created,
-// which is a privileged action on Windows.
 
-use run_make_support::{rfs, rust_lib_name, rustc};
+//@ ignore-windows-gnu
+// GNU Linker for Windows is non-deterministic.
+
+use run_make_support::{bin_name, is_windows_msvc, rfs, rust_lib_name, rustc};
 
 fn main() {
     // test 1: fat lto
     rustc().input("reproducible-build-aux.rs").run();
-    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
-    rfs::rename("reproducible-build", "reproducible-build-a");
-    rustc().input("reproducible-build.rs").arg("-Clto=fat").output("reproducible-build").run();
-    assert_eq!(rfs::read("reproducible-build"), rfs::read("reproducible-build-a"));
+    let make_reproducible_build = || {
+        let mut reproducible_build = rustc();
+        reproducible_build
+            .input("reproducible-build.rs")
+            .arg("-Clto=fat")
+            .output(bin_name("reproducible-build"));
+        if is_windows_msvc() {
+            // Avoids timestamps, etc. when linking.
+            reproducible_build.arg("-Clink-arg=/Brepro");
+        }
+        reproducible_build.run();
+    };
+    make_reproducible_build();
+    rfs::rename(bin_name("reproducible-build"), "reproducible-build-a");
+    if is_windows_msvc() {
+        // Linker acts differently if there is already a PDB file with the same
+        // name.
+        rfs::remove_file("reproducible-build.pdb");
+    }
+    make_reproducible_build();
+    assert_eq!(rfs::read(bin_name("reproducible-build")), rfs::read("reproducible-build-a"));
 
     // test 2: sysroot
     let sysroot = rustc().print("sysroot").run().stdout_utf8();
diff --git a/tests/run-make/sanitizer-dylib-link/program.rs b/tests/run-make/sanitizer-dylib-link/program.rs
index 1026c7f89ba..dbf885d343f 100644
--- a/tests/run-make/sanitizer-dylib-link/program.rs
+++ b/tests/run-make/sanitizer-dylib-link/program.rs
@@ -1,4 +1,4 @@
-#[cfg_attr(windows, link(name = "library.dll.lib", modifiers = "+verbatim"))]
+#[cfg_attr(windows, link(name = "library", kind = "raw-dylib"))]
 #[cfg_attr(not(windows), link(name = "library"))]
 extern "C" {
     fn overflow();
diff --git a/tests/rustdoc-js/big-result.rs b/tests/rustdoc-js/big-result.rs
index 4dfecd6aaad..c7a52aac1a2 100644
--- a/tests/rustdoc-js/big-result.rs
+++ b/tests/rustdoc-js/big-result.rs
@@ -1,4 +1,3 @@
-#![feature(concat_idents)]
 #![allow(nonstandard_style)]
 /// Generate 250 items that all match the query, starting with the longest.
 /// Those long items should be dropped from the result set, and the short ones
diff --git a/tests/rustdoc-json/attrs/cold.rs b/tests/rustdoc-json/attrs/cold.rs
new file mode 100644
index 00000000000..e219345d669
--- /dev/null
+++ b/tests/rustdoc-json/attrs/cold.rs
@@ -0,0 +1,3 @@
+//@ is "$.index[?(@.name=='cold_fn')].attrs" '["#[attr = Cold]"]'
+#[cold]
+pub fn cold_fn() {}
diff --git a/tests/rustdoc-json/attrs/optimize.rs b/tests/rustdoc-json/attrs/optimize.rs
new file mode 100644
index 00000000000..0bed0ad18c3
--- /dev/null
+++ b/tests/rustdoc-json/attrs/optimize.rs
@@ -0,0 +1,13 @@
+#![feature(optimize_attribute)]
+
+//@ is "$.index[?(@.name=='speed')].attrs" '["#[attr = Optimize(Speed)]"]'
+#[optimize(speed)]
+pub fn speed() {}
+
+//@ is "$.index[?(@.name=='size')].attrs" '["#[attr = Optimize(Size)]"]'
+#[optimize(size)]
+pub fn size() {}
+
+//@ is "$.index[?(@.name=='none')].attrs" '["#[attr = Optimize(DoNotOptimize)]"]'
+#[optimize(none)]
+pub fn none() {}
diff --git a/tests/ui/derives/nonsense-input-to-debug.rs b/tests/ui/derives/nonsense-input-to-debug.rs
new file mode 100644
index 00000000000..7dfa3cd616a
--- /dev/null
+++ b/tests/ui/derives/nonsense-input-to-debug.rs
@@ -0,0 +1,12 @@
+// Issue: #32950
+// Ensure that using macros rather than a type doesn't break `derive`.
+
+#[derive(Debug)]
+struct Nonsense<T> {
+    //~^ ERROR type parameter `T` is never used
+    should_be_vec_t: vec![T],
+    //~^ ERROR `derive` cannot be used on items with type macros
+    //~| ERROR expected type, found `expr` metavariable
+}
+
+fn main() {}
diff --git a/tests/ui/derives/nonsense-input-to-debug.stderr b/tests/ui/derives/nonsense-input-to-debug.stderr
new file mode 100644
index 00000000000..7c97ca93cfc
--- /dev/null
+++ b/tests/ui/derives/nonsense-input-to-debug.stderr
@@ -0,0 +1,30 @@
+error: `derive` cannot be used on items with type macros
+  --> $DIR/nonsense-input-to-debug.rs:7:22
+   |
+LL |     should_be_vec_t: vec![T],
+   |                      ^^^^^^^
+
+error: expected type, found `expr` metavariable
+  --> $DIR/nonsense-input-to-debug.rs:7:22
+   |
+LL |     should_be_vec_t: vec![T],
+   |                      ^^^^^^^
+   |                      |
+   |                      expected type
+   |                      in this macro invocation
+   |                      this macro call doesn't expand to a type
+   |
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/nonsense-input-to-debug.rs:5:17
+   |
+LL | struct Nonsense<T> {
+   |                 ^ unused type parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.rs b/tests/ui/feature-gates/feature-gate-concat_idents.rs
deleted file mode 100644
index 4fc3b691597..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-const XY_1: i32 = 10;
-
-fn main() {
-    const XY_2: i32 = 20;
-    let a = concat_idents!(X, Y_1); //~ ERROR `concat_idents` is not stable
-    let b = concat_idents!(X, Y_2); //~ ERROR `concat_idents` is not stable
-    assert_eq!(a, 10);
-    assert_eq!(b, 20);
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents.stderr b/tests/ui/feature-gates/feature-gate-concat_idents.stderr
deleted file mode 100644
index 6399424eecd..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents.rs:7:13
-   |
-LL |     let a = concat_idents!(X, Y_1);
-   |             ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents.rs:8:13
-   |
-LL |     let b = concat_idents!(X, Y_2);
-   |             ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.rs b/tests/ui/feature-gates/feature-gate-concat_idents2.rs
deleted file mode 100644
index bc2b4f7cddf..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents2.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-fn main() {
-    concat_idents!(a, b); //~ ERROR `concat_idents` is not stable enough
-                          //~| ERROR cannot find value `ab` in this scope
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr b/tests/ui/feature-gates/feature-gate-concat_idents2.stderr
deleted file mode 100644
index a770c1a348b..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents2.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents2.rs:4:5
-   |
-LL |     concat_idents!(a, b);
-   |     ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0425]: cannot find value `ab` in this scope
-  --> $DIR/feature-gate-concat_idents2.rs:4:5
-   |
-LL |     concat_idents!(a, b);
-   |     ^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0425, E0658.
-For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.rs b/tests/ui/feature-gates/feature-gate-concat_idents3.rs
deleted file mode 100644
index d4a0d2e6bb0..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents3.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-#![expect(deprecated)] // concat_idents is deprecated
-
-const XY_1: i32 = 10;
-
-fn main() {
-    const XY_2: i32 = 20;
-    assert_eq!(10, concat_idents!(X, Y_1)); //~ ERROR `concat_idents` is not stable
-    assert_eq!(20, concat_idents!(X, Y_2)); //~ ERROR `concat_idents` is not stable
-}
diff --git a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr b/tests/ui/feature-gates/feature-gate-concat_idents3.stderr
deleted file mode 100644
index 7d929322bc0..00000000000
--- a/tests/ui/feature-gates/feature-gate-concat_idents3.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents3.rs:7:20
-   |
-LL |     assert_eq!(10, concat_idents!(X, Y_1));
-   |                    ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `concat_idents`: `concat_idents` is not stable enough for use and is subject to change
-  --> $DIR/feature-gate-concat_idents3.rs:8:20
-   |
-LL |     assert_eq!(20, concat_idents!(X, Y_2));
-   |                    ^^^^^^^^^^^^^
-   |
-   = note: see issue #29599 <https://github.com/rust-lang/rust/issues/29599> for more information
-   = help: add `#![feature(concat_idents)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/issues/issue-32950.rs b/tests/ui/issues/issue-32950.rs
deleted file mode 100644
index b51ac296776..00000000000
--- a/tests/ui/issues/issue-32950.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-#[derive(Debug)]
-struct Baz<T>(
-    concat_idents!(Foo, Bar) //~ ERROR `derive` cannot be used on items with type macros
-                             //~^ ERROR cannot find type `FooBar` in this scope
-);
-
-fn main() {}
diff --git a/tests/ui/issues/issue-32950.stderr b/tests/ui/issues/issue-32950.stderr
deleted file mode 100644
index 38a82542f89..00000000000
--- a/tests/ui/issues/issue-32950.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: `derive` cannot be used on items with type macros
-  --> $DIR/issue-32950.rs:6:5
-   |
-LL |     concat_idents!(Foo, Bar)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0412]: cannot find type `FooBar` in this scope
-  --> $DIR/issue-32950.rs:6:5
-   |
-LL |     concat_idents!(Foo, Bar)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/issues/issue-50403.rs b/tests/ui/issues/issue-50403.rs
deleted file mode 100644
index f14958afc34..00000000000
--- a/tests/ui/issues/issue-50403.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-fn main() {
-    let x = concat_idents!(); //~ ERROR `concat_idents!()` takes 1 or more arguments
-}
diff --git a/tests/ui/issues/issue-50403.stderr b/tests/ui/issues/issue-50403.stderr
deleted file mode 100644
index e7dd05bb018..00000000000
--- a/tests/ui/issues/issue-50403.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: `concat_idents!()` takes 1 or more arguments
-  --> $DIR/issue-50403.rs:5:13
-   |
-LL |     let x = concat_idents!();
-   |             ^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/macros/macro-comma-support-rpass.rs b/tests/ui/macros/macro-comma-support-rpass.rs
index 5a4bac70b1c..ef6c1ff6fd0 100644
--- a/tests/ui/macros/macro-comma-support-rpass.rs
+++ b/tests/ui/macros/macro-comma-support-rpass.rs
@@ -15,7 +15,6 @@
 #![cfg_attr(core, no_std)]
 
 #![allow(deprecated)] // for deprecated `try!()` macro
-#![feature(concat_idents)]
 
 #[cfg(std)] use std::fmt;
 #[cfg(core)] use core::fmt;
@@ -80,17 +79,6 @@ fn concat() {
 }
 
 #[test]
-fn concat_idents() {
-    fn foo() {}
-    fn foobar() {}
-
-    concat_idents!(foo)();
-    concat_idents!(foo,)();
-    concat_idents!(foo, bar)();
-    concat_idents!(foo, bar,)();
-}
-
-#[test]
 fn debug_assert() {
     debug_assert!(true);
     debug_assert!(true, );
diff --git a/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs b/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs
new file mode 100644
index 00000000000..caad63c5f6b
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/empty-input.rs
@@ -0,0 +1,12 @@
+// Issue 50403
+// Ensure that `concat` can't create empty identifiers
+// FIXME(macro_metavar_expr_concat): this error message could be improved
+
+macro_rules! empty {
+    () => { ${concat()} } //~ ERROR expected identifier or string literal
+                          //~^ERROR expected expression
+}
+
+fn main() {
+    let x = empty!();
+}
diff --git a/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr b/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr
new file mode 100644
index 00000000000..e95032dd247
--- /dev/null
+++ b/tests/ui/macros/macro-metavar-expr-concat/empty-input.stderr
@@ -0,0 +1,19 @@
+error: expected identifier or string literal
+  --> $DIR/empty-input.rs:6:14
+   |
+LL |     () => { ${concat()} }
+   |              ^^^^^^^^^^
+
+error: expected expression, found `$`
+  --> $DIR/empty-input.rs:6:13
+   |
+LL |     () => { ${concat()} }
+   |             ^ expected expression
+...
+LL |     let x = empty!();
+   |             -------- in this macro invocation
+   |
+   = note: this error originates in the macro `empty` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macros-nonfatal-errors.rs b/tests/ui/macros/macros-nonfatal-errors.rs
index 091d64ea5d9..1349d741510 100644
--- a/tests/ui/macros/macros-nonfatal-errors.rs
+++ b/tests/ui/macros/macros-nonfatal-errors.rs
@@ -3,9 +3,8 @@
 // test that errors in a (selection) of macros don't kill compilation
 // immediately, so that we get more errors listed at a time.
 
-#![feature(trace_macros, concat_idents)]
+#![feature(trace_macros)]
 #![feature(stmt_expr_attributes)]
-#![expect(deprecated)] // concat_idents is deprecated
 
 use std::arch::asm;
 
@@ -105,8 +104,6 @@ fn main() {
     asm!(invalid); //~ ERROR
     llvm_asm!(invalid); //~ ERROR
 
-    concat_idents!("not", "idents"); //~ ERROR
-
     option_env!(invalid); //~ ERROR
     env!(invalid); //~ ERROR
     env!(foo, abr, baz); //~ ERROR
diff --git a/tests/ui/macros/macros-nonfatal-errors.stderr b/tests/ui/macros/macros-nonfatal-errors.stderr
index 2f990cb24e2..bc34bd1c8ec 100644
--- a/tests/ui/macros/macros-nonfatal-errors.stderr
+++ b/tests/ui/macros/macros-nonfatal-errors.stderr
@@ -1,5 +1,5 @@
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:14:5
+  --> $DIR/macros-nonfatal-errors.rs:13:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:19:36
+  --> $DIR/macros-nonfatal-errors.rs:18:36
    |
 LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    |                                    ^^^^^^^^^^
@@ -15,7 +15,7 @@ LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:23:1
+  --> $DIR/macros-nonfatal-errors.rs:22:1
    |
 LL | #[default]
    | ^^^^^^^^^^
@@ -23,7 +23,7 @@ LL | #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:27:1
+  --> $DIR/macros-nonfatal-errors.rs:26:1
    |
 LL | #[default]
    | ^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | #[default]
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:37:11
+  --> $DIR/macros-nonfatal-errors.rs:36:11
    |
 LL |     Foo = #[default] 0,
    |           ^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     Foo = #[default] 0,
    = help: consider a manual implementation of `Default`
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:38:14
+  --> $DIR/macros-nonfatal-errors.rs:37:14
    |
 LL |     Bar([u8; #[default] 1]),
    |              ^^^^^^^^^^
@@ -47,7 +47,7 @@ LL |     Bar([u8; #[default] 1]),
    = help: consider a manual implementation of `Default`
 
 error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
-  --> $DIR/macros-nonfatal-errors.rs:43:10
+  --> $DIR/macros-nonfatal-errors.rs:42:10
    |
 LL |   #[derive(Default)]
    |            ^^^^^^^
@@ -67,7 +67,7 @@ LL |     #[default] Bar,
    |     ++++++++++
 
 error[E0665]: `#[derive(Default)]` on enum with no `#[default]`
-  --> $DIR/macros-nonfatal-errors.rs:49:10
+  --> $DIR/macros-nonfatal-errors.rs:48:10
    |
 LL |   #[derive(Default)]
    |            ^^^^^^^
@@ -78,7 +78,7 @@ LL | | }
    | |_- this enum needs a unit variant marked with `#[default]`
 
 error: multiple declared defaults
-  --> $DIR/macros-nonfatal-errors.rs:55:10
+  --> $DIR/macros-nonfatal-errors.rs:54:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -95,7 +95,7 @@ LL |     Baz,
    = note: only one variant can be default
 
 error: `#[default]` attribute does not accept a value
-  --> $DIR/macros-nonfatal-errors.rs:67:5
+  --> $DIR/macros-nonfatal-errors.rs:66:5
    |
 LL |     #[default = 1]
    |     ^^^^^^^^^^^^^^
@@ -103,7 +103,7 @@ LL |     #[default = 1]
    = help: try using `#[default]`
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:75:5
+  --> $DIR/macros-nonfatal-errors.rs:74:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -114,13 +114,13 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing this
-  --> $DIR/macros-nonfatal-errors.rs:74:5
+  --> $DIR/macros-nonfatal-errors.rs:73:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:85:5
+  --> $DIR/macros-nonfatal-errors.rs:84:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -132,7 +132,7 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing these
-  --> $DIR/macros-nonfatal-errors.rs:82:5
+  --> $DIR/macros-nonfatal-errors.rs:81:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -142,7 +142,7 @@ LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:92:5
+  --> $DIR/macros-nonfatal-errors.rs:91:5
    |
 LL |     Foo {},
    |     ^^^
@@ -150,7 +150,7 @@ LL |     Foo {},
    = help: consider a manual implementation of `Default`
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:100:5
+  --> $DIR/macros-nonfatal-errors.rs:99:5
    |
 LL |     #[non_exhaustive]
    |     ----------------- declared `#[non_exhaustive]` here
@@ -160,37 +160,31 @@ LL |     Foo,
    = help: consider a manual implementation of `Default`
 
 error: asm template must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:105:10
+  --> $DIR/macros-nonfatal-errors.rs:104:10
    |
 LL |     asm!(invalid);
    |          ^^^^^^^
 
-error: `concat_idents!()` requires ident args
-  --> $DIR/macros-nonfatal-errors.rs:108:5
-   |
-LL |     concat_idents!("not", "idents");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:110:17
+  --> $DIR/macros-nonfatal-errors.rs:107:17
    |
 LL |     option_env!(invalid);
    |                 ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:111:10
+  --> $DIR/macros-nonfatal-errors.rs:108:10
    |
 LL |     env!(invalid);
    |          ^^^^^^^
 
 error: `env!()` takes 1 or 2 arguments
-  --> $DIR/macros-nonfatal-errors.rs:112:5
+  --> $DIR/macros-nonfatal-errors.rs:109:5
    |
 LL |     env!(foo, abr, baz);
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined at compile time
-  --> $DIR/macros-nonfatal-errors.rs:113:5
+  --> $DIR/macros-nonfatal-errors.rs:110:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +192,7 @@ LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    = help: use `std::env::var("RUST_HOPEFULLY_THIS_DOESNT_EXIST")` to read the variable at run time
 
 error: format argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:115:13
+  --> $DIR/macros-nonfatal-errors.rs:112:13
    |
 LL |     format!(invalid);
    |             ^^^^^^^
@@ -209,43 +203,43 @@ LL |     format!("{}", invalid);
    |             +++++
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:117:14
+  --> $DIR/macros-nonfatal-errors.rs:114:14
    |
 LL |     include!(invalid);
    |              ^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:119:18
+  --> $DIR/macros-nonfatal-errors.rs:116:18
    |
 LL |     include_str!(invalid);
    |                  ^^^^^^^
 
 error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
-  --> $DIR/macros-nonfatal-errors.rs:120:5
+  --> $DIR/macros-nonfatal-errors.rs:117:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:121:20
+  --> $DIR/macros-nonfatal-errors.rs:118:20
    |
 LL |     include_bytes!(invalid);
    |                    ^^^^^^^
 
 error: couldn't read `$DIR/i'd be quite surprised if a file with this name existed`: $FILE_NOT_FOUND_MSG
-  --> $DIR/macros-nonfatal-errors.rs:122:5
+  --> $DIR/macros-nonfatal-errors.rs:119:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: trace_macros! accepts only `true` or `false`
-  --> $DIR/macros-nonfatal-errors.rs:124:5
+  --> $DIR/macros-nonfatal-errors.rs:121:5
    |
 LL |     trace_macros!(invalid);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:134:9
+  --> $DIR/macros-nonfatal-errors.rs:131:9
    |
 LL |         #[non_exhaustive]
    |         ----------------- declared `#[non_exhaustive]` here
@@ -255,11 +249,11 @@ LL |         Foo,
    = help: consider a manual implementation of `Default`
 
 error: cannot find macro `llvm_asm` in this scope
-  --> $DIR/macros-nonfatal-errors.rs:106:5
+  --> $DIR/macros-nonfatal-errors.rs:105:5
    |
 LL |     llvm_asm!(invalid);
    |     ^^^^^^^^
 
-error: aborting due to 29 previous errors
+error: aborting due to 28 previous errors
 
 For more information about this error, try `rustc --explain E0665`.
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index 88f91bef30b..b3b8784fa27 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -1,52 +1,7 @@
-ast-stats POST EXPANSION AST STATS
+ast-stats ================================================================
+ast-stats POST EXPANSION AST STATS: input_stats
 ast-stats Name                Accumulated Size         Count     Item Size
 ast-stats ----------------------------------------------------------------
-ast-stats Crate                     40 (NN.N%)             1            40
-ast-stats GenericArgs               40 (NN.N%)             1            40
-ast-stats - AngleBracketed            40 (NN.N%)             1
-ast-stats ExprField                 48 (NN.N%)             1            48
-ast-stats WherePredicate            72 (NN.N%)             1            72
-ast-stats - BoundPredicate            72 (NN.N%)             1
-ast-stats ForeignItem               80 (NN.N%)             1            80
-ast-stats - Fn                        80 (NN.N%)             1
-ast-stats Arm                       96 (NN.N%)             2            48
-ast-stats Local                     96 (NN.N%)             1            96
-ast-stats FnDecl                   120 (NN.N%)             5            24
-ast-stats InlineAsm                120 (NN.N%)             1           120
-ast-stats Attribute                128 (NN.N%)             4            32
-ast-stats - DocComment                32 (NN.N%)             1
-ast-stats - Normal                    96 (NN.N%)             3
-ast-stats Param                    160 (NN.N%)             4            40
-ast-stats Stmt                     160 (NN.N%)             5            32
-ast-stats - Let                       32 (NN.N%)             1
-ast-stats - Semi                      32 (NN.N%)             1
-ast-stats - Expr                      96 (NN.N%)             3
-ast-stats Block                    192 (NN.N%)             6            32
-ast-stats FieldDef                 208 (NN.N%)             2           104
-ast-stats Variant                  208 (NN.N%)             2           104
-ast-stats AssocItem                320 (NN.N%)             4            80
-ast-stats - Fn                       160 (NN.N%)             2
-ast-stats - Type                     160 (NN.N%)             2
-ast-stats GenericBound             352 (NN.N%)             4            88
-ast-stats - Trait                    352 (NN.N%)             4
-ast-stats GenericParam             480 (NN.N%)             5            96
-ast-stats Pat                      504 (NN.N%)             7            72
-ast-stats - Struct                    72 (NN.N%)             1
-ast-stats - Wild                      72 (NN.N%)             1
-ast-stats - Ident                    360 (NN.N%)             5
-ast-stats Expr                     648 (NN.N%)             9            72
-ast-stats - InlineAsm                 72 (NN.N%)             1
-ast-stats - Match                     72 (NN.N%)             1
-ast-stats - Path                      72 (NN.N%)             1
-ast-stats - Struct                    72 (NN.N%)             1
-ast-stats - Lit                      144 (NN.N%)             2
-ast-stats - Block                    216 (NN.N%)             3
-ast-stats PathSegment              864 (NN.N%)            36            24
-ast-stats Ty                       896 (NN.N%)            14            64
-ast-stats - Ptr                       64 (NN.N%)             1
-ast-stats - Ref                       64 (NN.N%)             1
-ast-stats - ImplicitSelf             128 (NN.N%)             2
-ast-stats - Path                     640 (NN.N%)            10
 ast-stats Item                   1_584 (NN.N%)            11           144
 ast-stats - Enum                     144 (NN.N%)             1
 ast-stats - ExternCrate              144 (NN.N%)             1
@@ -55,57 +10,61 @@ ast-stats - Impl                     144 (NN.N%)             1
 ast-stats - Trait                    144 (NN.N%)             1
 ast-stats - Fn                       288 (NN.N%)             2
 ast-stats - Use                      576 (NN.N%)             4
+ast-stats Ty                       896 (NN.N%)            14            64
+ast-stats - Ptr                       64 (NN.N%)             1
+ast-stats - Ref                       64 (NN.N%)             1
+ast-stats - ImplicitSelf             128 (NN.N%)             2
+ast-stats - Path                     640 (NN.N%)            10
+ast-stats PathSegment              864 (NN.N%)            36            24
+ast-stats Expr                     648 (NN.N%)             9            72
+ast-stats - InlineAsm                 72 (NN.N%)             1
+ast-stats - Match                     72 (NN.N%)             1
+ast-stats - Path                      72 (NN.N%)             1
+ast-stats - Struct                    72 (NN.N%)             1
+ast-stats - Lit                      144 (NN.N%)             2
+ast-stats - Block                    216 (NN.N%)             3
+ast-stats Pat                      504 (NN.N%)             7            72
+ast-stats - Struct                    72 (NN.N%)             1
+ast-stats - Wild                      72 (NN.N%)             1
+ast-stats - Ident                    360 (NN.N%)             5
+ast-stats GenericParam             480 (NN.N%)             5            96
+ast-stats GenericBound             352 (NN.N%)             4            88
+ast-stats - Trait                    352 (NN.N%)             4
+ast-stats AssocItem                320 (NN.N%)             4            80
+ast-stats - Fn                       160 (NN.N%)             2
+ast-stats - Type                     160 (NN.N%)             2
+ast-stats Variant                  208 (NN.N%)             2           104
+ast-stats FieldDef                 208 (NN.N%)             2           104
+ast-stats Block                    192 (NN.N%)             6            32
+ast-stats Stmt                     160 (NN.N%)             5            32
+ast-stats - Let                       32 (NN.N%)             1
+ast-stats - Semi                      32 (NN.N%)             1
+ast-stats - Expr                      96 (NN.N%)             3
+ast-stats Param                    160 (NN.N%)             4            40
+ast-stats Attribute                128 (NN.N%)             4            32
+ast-stats - DocComment                32 (NN.N%)             1
+ast-stats - Normal                    96 (NN.N%)             3
+ast-stats InlineAsm                120 (NN.N%)             1           120
+ast-stats FnDecl                   120 (NN.N%)             5            24
+ast-stats Local                     96 (NN.N%)             1            96
+ast-stats Arm                       96 (NN.N%)             2            48
+ast-stats ForeignItem               80 (NN.N%)             1            80
+ast-stats - Fn                        80 (NN.N%)             1
+ast-stats WherePredicate            72 (NN.N%)             1            72
+ast-stats - BoundPredicate            72 (NN.N%)             1
+ast-stats ExprField                 48 (NN.N%)             1            48
+ast-stats GenericArgs               40 (NN.N%)             1            40
+ast-stats - AngleBracketed            40 (NN.N%)             1
+ast-stats Crate                     40 (NN.N%)             1            40
 ast-stats ----------------------------------------------------------------
 ast-stats Total                  7_416                   127
-ast-stats
-hir-stats HIR STATS
+ast-stats ================================================================
+hir-stats ================================================================
+hir-stats HIR STATS: input_stats
 hir-stats Name                Accumulated Size         Count     Item Size
 hir-stats ----------------------------------------------------------------
-hir-stats ForeignItemRef            24 (NN.N%)             1            24
-hir-stats Lifetime                  28 (NN.N%)             1            28
-hir-stats Mod                       32 (NN.N%)             1            32
-hir-stats ExprField                 40 (NN.N%)             1            40
-hir-stats TraitItemRef              56 (NN.N%)             2            28
-hir-stats GenericArg                64 (NN.N%)             4            16
-hir-stats - Type                      16 (NN.N%)             1
-hir-stats - Lifetime                  48 (NN.N%)             3
-hir-stats Param                     64 (NN.N%)             2            32
-hir-stats Body                      72 (NN.N%)             3            24
-hir-stats ImplItemRef               72 (NN.N%)             2            36
-hir-stats InlineAsm                 72 (NN.N%)             1            72
-hir-stats Local                     72 (NN.N%)             1            72
-hir-stats WherePredicate            72 (NN.N%)             3            24
-hir-stats - BoundPredicate            72 (NN.N%)             3
-hir-stats Arm                       80 (NN.N%)             2            40
-hir-stats Stmt                      96 (NN.N%)             3            32
-hir-stats - Expr                      32 (NN.N%)             1
-hir-stats - Let                       32 (NN.N%)             1
-hir-stats - Semi                      32 (NN.N%)             1
-hir-stats FnDecl                   120 (NN.N%)             3            40
-hir-stats FieldDef                 128 (NN.N%)             2            64
-hir-stats GenericArgs              144 (NN.N%)             3            48
-hir-stats Variant                  144 (NN.N%)             2            72
-hir-stats Attribute                160 (NN.N%)             4            40
-hir-stats GenericBound             256 (NN.N%)             4            64
-hir-stats - Trait                    256 (NN.N%)             4
-hir-stats Block                    288 (NN.N%)             6            48
-hir-stats Pat                      360 (NN.N%)             5            72
-hir-stats - Struct                    72 (NN.N%)             1
-hir-stats - Wild                      72 (NN.N%)             1
-hir-stats - Binding                  216 (NN.N%)             3
-hir-stats GenericParam             400 (NN.N%)             5            80
-hir-stats Generics                 560 (NN.N%)            10            56
-hir-stats Ty                       720 (NN.N%)            15            48
-hir-stats - Ptr                       48 (NN.N%)             1
-hir-stats - Ref                       48 (NN.N%)             1
-hir-stats - Path                     624 (NN.N%)            13
-hir-stats Expr                     768 (NN.N%)            12            64
-hir-stats - InlineAsm                 64 (NN.N%)             1
-hir-stats - Match                     64 (NN.N%)             1
-hir-stats - Path                      64 (NN.N%)             1
-hir-stats - Struct                    64 (NN.N%)             1
-hir-stats - Lit                      128 (NN.N%)             2
-hir-stats - Block                    384 (NN.N%)             6
+hir-stats PathSegment            1_776 (NN.N%)            37            48
+hir-stats Path                   1_040 (NN.N%)            26            40
 hir-stats Item                     968 (NN.N%)            11            88
 hir-stats - Enum                      88 (NN.N%)             1
 hir-stats - ExternCrate               88 (NN.N%)             1
@@ -114,8 +73,51 @@ hir-stats - Impl                      88 (NN.N%)             1
 hir-stats - Trait                     88 (NN.N%)             1
 hir-stats - Fn                       176 (NN.N%)             2
 hir-stats - Use                      352 (NN.N%)             4
-hir-stats Path                   1_040 (NN.N%)            26            40
-hir-stats PathSegment            1_776 (NN.N%)            37            48
+hir-stats Expr                     768 (NN.N%)            12            64
+hir-stats - InlineAsm                 64 (NN.N%)             1
+hir-stats - Match                     64 (NN.N%)             1
+hir-stats - Path                      64 (NN.N%)             1
+hir-stats - Struct                    64 (NN.N%)             1
+hir-stats - Lit                      128 (NN.N%)             2
+hir-stats - Block                    384 (NN.N%)             6
+hir-stats Ty                       720 (NN.N%)            15            48
+hir-stats - Ptr                       48 (NN.N%)             1
+hir-stats - Ref                       48 (NN.N%)             1
+hir-stats - Path                     624 (NN.N%)            13
+hir-stats Generics                 560 (NN.N%)            10            56
+hir-stats GenericParam             400 (NN.N%)             5            80
+hir-stats Pat                      360 (NN.N%)             5            72
+hir-stats - Struct                    72 (NN.N%)             1
+hir-stats - Wild                      72 (NN.N%)             1
+hir-stats - Binding                  216 (NN.N%)             3
+hir-stats Block                    288 (NN.N%)             6            48
+hir-stats GenericBound             256 (NN.N%)             4            64
+hir-stats - Trait                    256 (NN.N%)             4
+hir-stats Attribute                160 (NN.N%)             4            40
+hir-stats Variant                  144 (NN.N%)             2            72
+hir-stats GenericArgs              144 (NN.N%)             3            48
+hir-stats FieldDef                 128 (NN.N%)             2            64
+hir-stats FnDecl                   120 (NN.N%)             3            40
+hir-stats Stmt                      96 (NN.N%)             3            32
+hir-stats - Expr                      32 (NN.N%)             1
+hir-stats - Let                       32 (NN.N%)             1
+hir-stats - Semi                      32 (NN.N%)             1
+hir-stats Arm                       80 (NN.N%)             2            40
+hir-stats WherePredicate            72 (NN.N%)             3            24
+hir-stats - BoundPredicate            72 (NN.N%)             3
+hir-stats Local                     72 (NN.N%)             1            72
+hir-stats InlineAsm                 72 (NN.N%)             1            72
+hir-stats ImplItemRef               72 (NN.N%)             2            36
+hir-stats Body                      72 (NN.N%)             3            24
+hir-stats Param                     64 (NN.N%)             2            32
+hir-stats GenericArg                64 (NN.N%)             4            16
+hir-stats - Type                      16 (NN.N%)             1
+hir-stats - Lifetime                  48 (NN.N%)             3
+hir-stats TraitItemRef              56 (NN.N%)             2            28
+hir-stats ExprField                 40 (NN.N%)             1            40
+hir-stats Mod                       32 (NN.N%)             1            32
+hir-stats Lifetime                  28 (NN.N%)             1            28
+hir-stats ForeignItemRef            24 (NN.N%)             1            24
 hir-stats ----------------------------------------------------------------
 hir-stats Total                  8_676                   172
-hir-stats
+hir-stats ================================================================
diff --git a/tests/ui/syntax-extension-minor.rs b/tests/ui/syntax-extension-minor.rs
deleted file mode 100644
index 826990a89a5..00000000000
--- a/tests/ui/syntax-extension-minor.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ run-pass
-
-#![feature(concat_idents)]
-#![expect(deprecated)] // concat_idents is deprecated
-
-pub fn main() {
-    struct Foo;
-    let _: concat_idents!(F, oo) = Foo; // Test that `concat_idents!` can be used in type positions
-
-    let asdf_fdsa = "<.<".to_string();
-    // concat_idents should have call-site hygiene.
-    assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
-
-    assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
-}
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout
index cd1a5d0af08..ae44d1206af 100644
--- a/tests/ui/unpretty/exhaustive.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -12,7 +12,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -309,7 +308,6 @@ mod expressions {
 
 
 
-        // concat_idents is deprecated
 
 
 
@@ -622,8 +620,12 @@ mod types {
         /*! there is no syntax for this */
     }
     /// TyKind::MacCall
-    #[expect(deprecated)]
-    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    fn ty_mac_call() {
+        macro_rules! ty { ($ty:ty) => { $ty } }
+        let _: T;
+        let _: T;
+        let _: T;
+    }
     /// TyKind::CVarArgs
     fn ty_c_var_args() {
         /*! FIXME: todo */
diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr
index 58f7ff0f598..1c78cf98c59 100644
--- a/tests/ui/unpretty/exhaustive.hir.stderr
+++ b/tests/ui/unpretty/exhaustive.hir.stderr
@@ -1,17 +1,17 @@
 error[E0697]: closures cannot be static
-  --> $DIR/exhaustive.rs:211:9
+  --> $DIR/exhaustive.rs:210:9
    |
 LL |         static || value;
    |         ^^^^^^^^^
 
 error[E0697]: closures cannot be static
-  --> $DIR/exhaustive.rs:212:9
+  --> $DIR/exhaustive.rs:211:9
    |
 LL |         static move || value;
    |         ^^^^^^^^^^^^^^
 
 error[E0728]: `await` is only allowed inside `async` functions and blocks
-  --> $DIR/exhaustive.rs:241:13
+  --> $DIR/exhaustive.rs:240:13
    |
 LL |     fn expr_await() {
    |     --------------- this is not `async`
@@ -20,19 +20,19 @@ LL |         fut.await;
    |             ^^^^^ only allowed inside `async` functions and blocks
 
 error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/exhaustive.rs:290:9
+  --> $DIR/exhaustive.rs:289:9
    |
 LL |         _;
    |         ^ `_` not allowed here
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:300:9
+  --> $DIR/exhaustive.rs:299:9
    |
 LL |         x::();
    |         ^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:301:9
+  --> $DIR/exhaustive.rs:300:9
    |
 LL |         x::(T, T) -> T;
    |         ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
@@ -44,31 +44,31 @@ LL +         x::<T, T> -> T;
    |
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:302:9
+  --> $DIR/exhaustive.rs:301:9
    |
 LL |         crate::() -> ()::expressions::() -> ()::expr_path;
    |         ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:302:26
+  --> $DIR/exhaustive.rs:301:26
    |
 LL |         crate::() -> ()::expressions::() -> ()::expr_path;
    |                          ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:305:9
+  --> $DIR/exhaustive.rs:304:9
    |
 LL |         core::()::marker::()::PhantomData;
    |         ^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:305:19
+  --> $DIR/exhaustive.rs:304:19
    |
 LL |         core::()::marker::()::PhantomData;
    |                   ^^^^^^^^^^ only `Fn` traits may use parentheses
 
 error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks
-  --> $DIR/exhaustive.rs:392:9
+  --> $DIR/exhaustive.rs:391:9
    |
 LL |         yield;
    |         ^^^^^
@@ -79,7 +79,7 @@ LL |     #[coroutine] fn expr_yield() {
    |     ++++++++++++
 
 error[E0703]: invalid ABI: found `C++`
-  --> $DIR/exhaustive.rs:472:23
+  --> $DIR/exhaustive.rs:471:23
    |
 LL |         unsafe extern "C++" {}
    |                       ^^^^^ invalid ABI
@@ -87,7 +87,7 @@ LL |         unsafe extern "C++" {}
    = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
 
 error: `..` patterns are not allowed here
-  --> $DIR/exhaustive.rs:679:13
+  --> $DIR/exhaustive.rs:678:13
    |
 LL |         let ..;
    |             ^^
@@ -95,13 +95,13 @@ LL |         let ..;
    = note: only allowed in tuple, tuple struct, and slice patterns
 
 error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
-  --> $DIR/exhaustive.rs:794:16
+  --> $DIR/exhaustive.rs:793:16
    |
 LL |         let _: T() -> !;
    |                ^^^^^^^^ only `Fn` traits may use parentheses
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:809:16
+  --> $DIR/exhaustive.rs:808:16
    |
 LL |         let _: impl Send;
    |                ^^^^^^^^^
@@ -112,7 +112,7 @@ LL |         let _: impl Send;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:810:16
+  --> $DIR/exhaustive.rs:809:16
    |
 LL |         let _: impl Send + 'static;
    |                ^^^^^^^^^^^^^^^^^^^
@@ -123,7 +123,7 @@ LL |         let _: impl Send + 'static;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:811:16
+  --> $DIR/exhaustive.rs:810:16
    |
 LL |         let _: impl 'static + Send;
    |                ^^^^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL |         let _: impl 'static + Send;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:812:16
+  --> $DIR/exhaustive.rs:811:16
    |
 LL |         let _: impl ?Sized;
    |                ^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL |         let _: impl ?Sized;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:813:16
+  --> $DIR/exhaustive.rs:812:16
    |
 LL |         let _: impl ~const Clone;
    |                ^^^^^^^^^^^^^^^^^
@@ -156,7 +156,7 @@ LL |         let _: impl ~const Clone;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0562]: `impl Trait` is not allowed in the type of variable bindings
-  --> $DIR/exhaustive.rs:814:16
+  --> $DIR/exhaustive.rs:813:16
    |
 LL |         let _: impl for<'a> Send;
    |                ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index b15c02003a6..2d347ec6e88 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -11,7 +11,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -343,7 +342,6 @@ mod expressions {
 
 
 
-        // concat_idents is deprecated
 
 
 
@@ -685,8 +683,12 @@ mod types {
     /** there is no syntax for this */
     fn ty_implicit_self() { }
     /// TyKind::MacCall
-    #[expect(deprecated)]
-    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    fn ty_mac_call() {
+        macro_rules! ty { ($ty:ty) => { $ty } }
+        let _: T;
+        let _: T;
+        let _: T;
+    }
     /// TyKind::CVarArgs
     /** FIXME: todo */
     fn ty_c_var_args() { }
diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs
index 60ad3564689..ccf907a6165 100644
--- a/tests/ui/unpretty/exhaustive.rs
+++ b/tests/ui/unpretty/exhaustive.rs
@@ -11,7 +11,6 @@
 #![feature(auto_traits)]
 #![feature(box_patterns)]
 #![feature(builtin_syntax)]
-#![feature(concat_idents)]
 #![feature(const_trait_impl)]
 #![feature(decl_macro)]
 #![feature(deref_patterns)]
@@ -835,11 +834,13 @@ mod types {
     }
 
     /// TyKind::MacCall
-    #[expect(deprecated)] // concat_idents is deprecated
     fn ty_mac_call() {
-        let _: concat_idents!(T);
-        let _: concat_idents![T];
-        let _: concat_idents! { T };
+        macro_rules! ty {
+            ($ty:ty) => { $ty }
+        }
+        let _: ty!(T);
+        let _: ty![T];
+        let _: ty! { T };
     }
 
     /// TyKind::CVarArgs