about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs155
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/back/lto.rs21
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs37
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs155
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/mod.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs84
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs11
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs6
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/naked_asm.rs266
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/place.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs35
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs9
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs62
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/asm.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs9
26 files changed, 660 insertions, 290 deletions
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 11bcd727501..ab65319e3d3 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -26,15 +26,14 @@
 use std::borrow::Cow;
 use std::fmt;
 
-use rustc_ast as ast;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::{DiagArgValue, IntoDiagArg};
+use rustc_hir as hir;
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::mir::mono::CodegenUnitNameBuilder;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 use tracing::debug;
 
@@ -77,7 +76,7 @@ struct AssertModuleSource<'tcx> {
 }
 
 impl<'tcx> AssertModuleSource<'tcx> {
-    fn check_attr(&mut self, attr: &ast::Attribute) {
+    fn check_attr(&mut self, attr: &hir::Attribute) {
         let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
             (CguReuse::PreLto, ComparisonKind::AtLeast)
         } else if attr.has_name(sym::rustc_partition_codegened) {
@@ -158,7 +157,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         );
     }
 
-    fn field(&self, attr: &ast::Attribute, name: Symbol) -> Symbol {
+    fn field(&self, attr: &hir::Attribute, name: Symbol) -> Symbol {
         for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) {
             if item.has_name(name) {
                 if let Some(value) = item.value_str() {
@@ -177,7 +176,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
 
     /// Scan for a `cfg="foo"` attribute and check whether we have a
     /// cfg flag called `foo`.
-    fn check_config(&self, attr: &ast::Attribute) -> bool {
+    fn check_config(&self, attr: &hir::Attribute) -> bool {
         let config = &self.tcx.sess.psess.config;
         let value = self.field(attr, sym::cfg);
         debug!("check_config(config={:?}, value={:?})", config, value);
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index d4836eb7a1d..58eb137c068 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -2,7 +2,7 @@ use std::env;
 use std::error::Error;
 use std::ffi::OsString;
 use std::fs::{self, File};
-use std::io::{self, Write};
+use std::io::{self, BufWriter, Write};
 use std::path::{Path, PathBuf};
 
 use ar_archive_writer::{
@@ -14,7 +14,7 @@ use object::read::macho::FatArch;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::memmap::Mmap;
 use rustc_session::Session;
-use rustc_span::symbol::Symbol;
+use rustc_span::Symbol;
 use tempfile::Builder as TempFileBuilder;
 use tracing::trace;
 
@@ -509,9 +509,10 @@ impl<'a> ArArchiveBuilder<'a> {
                 io_error_context("couldn't create a directory for the temp file", err)
             })?;
         let archive_tmpfile_path = archive_tmpdir.path().join("tmp.a");
-        let mut archive_tmpfile = File::create_new(&archive_tmpfile_path)
+        let archive_tmpfile = File::create_new(&archive_tmpfile_path)
             .map_err(|err| io_error_context("couldn't create the temp file", err))?;
 
+        let mut archive_tmpfile = BufWriter::new(archive_tmpfile);
         write_archive_to_stream(
             &mut archive_tmpfile,
             &entries,
@@ -519,6 +520,8 @@ impl<'a> ArArchiveBuilder<'a> {
             false,
             /* is_ec = */ self.sess.target.arch == "arm64ec",
         )?;
+        archive_tmpfile.flush()?;
+        drop(archive_tmpfile);
 
         let any_entries = !entries.is_empty();
         drop(entries);
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index c3281c8c2e5..2587d6dfdc4 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -15,7 +15,7 @@ use rustc_ast::CRATE_NODE_ID;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, FatalError};
+use rustc_errors::DiagCtxtHandle;
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
@@ -35,7 +35,7 @@ use rustc_session::utils::NativeLibKind;
 /// For all the linkers we support, and information they might
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{Session, filesearch};
-use rustc_span::symbol::Symbol;
+use rustc_span::Symbol;
 use rustc_target::spec::crt_objects::CrtObjects;
 use rustc_target::spec::{
     Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures,
@@ -71,7 +71,7 @@ pub fn link_binary(
     archive_builder_builder: &dyn ArchiveBuilderBuilder,
     codegen_results: CodegenResults,
     outputs: &OutputFilenames,
-) -> Result<(), ErrorGuaranteed> {
+) {
     let _timer = sess.timer("link_binary");
     let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
     let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
@@ -119,7 +119,7 @@ pub fn link_binary(
                         &codegen_results,
                         RlibFlavor::Normal,
                         &path,
-                    )?
+                    )
                     .build(&out_filename);
                 }
                 CrateType::Staticlib => {
@@ -129,7 +129,7 @@ pub fn link_binary(
                         &codegen_results,
                         &out_filename,
                         &path,
-                    )?;
+                    );
                 }
                 _ => {
                     link_natively(
@@ -139,7 +139,7 @@ pub fn link_binary(
                         &out_filename,
                         &codegen_results,
                         path.as_ref(),
-                    )?;
+                    );
                 }
             }
             if sess.opts.json_artifact_notifications {
@@ -225,8 +225,6 @@ pub fn link_binary(
             maybe_remove_temps_from_module(preserve_objects, preserve_dwarf_objects, module);
         }
     });
-
-    Ok(())
 }
 
 // Crate type is not passed when calculating the dylibs to include for LTO. In that case all
@@ -236,9 +234,13 @@ pub fn each_linked_rlib(
     crate_type: Option<CrateType>,
     f: &mut dyn FnMut(CrateNum, &Path),
 ) -> Result<(), errors::LinkRlibError> {
-    let crates = info.used_crates.iter();
+    let fmts = if let Some(crate_type) = crate_type {
+        let Some(fmts) = info.dependency_formats.get(&crate_type) else {
+            return Err(errors::LinkRlibError::MissingFormat);
+        };
 
-    let fmts = if crate_type.is_none() {
+        fmts
+    } else {
         for combination in info.dependency_formats.iter().combinations(2) {
             let (ty1, list1) = &combination[0];
             let (ty2, list2) = &combination[1];
@@ -254,22 +256,12 @@ pub fn each_linked_rlib(
         if info.dependency_formats.is_empty() {
             return Err(errors::LinkRlibError::MissingFormat);
         }
-        &info.dependency_formats[0].1
-    } else {
-        let fmts = info
-            .dependency_formats
-            .iter()
-            .find_map(|&(ty, ref list)| if Some(ty) == crate_type { Some(list) } else { None });
-
-        let Some(fmts) = fmts else {
-            return Err(errors::LinkRlibError::MissingFormat);
-        };
-
-        fmts
+        info.dependency_formats.first().unwrap().1
     };
 
-    for &cnum in crates {
-        match fmts.get(cnum.as_usize() - 1) {
+    let used_dep_crates = info.used_crates.iter();
+    for &cnum in used_dep_crates {
+        match fmts.get(cnum) {
             Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
             Some(_) => {}
             None => return Err(errors::LinkRlibError::MissingFormat),
@@ -298,7 +290,7 @@ fn link_rlib<'a>(
     codegen_results: &CodegenResults,
     flavor: RlibFlavor,
     tmpdir: &MaybeTempDir,
-) -> Result<Box<dyn ArchiveBuilder + 'a>, ErrorGuaranteed> {
+) -> Box<dyn ArchiveBuilder + 'a> {
     let mut ab = archive_builder_builder.new_archive_builder(sess);
 
     let trailing_metadata = match flavor {
@@ -374,7 +366,7 @@ fn link_rlib<'a>(
         {
             let path = find_native_static_library(filename.as_str(), true, sess);
             let src = read(path)
-                .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?;
+                .unwrap_or_else(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }));
             let (data, _) = create_wrapper_file(sess, ".bundled_lib".to_string(), &src);
             let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
             packed_bundled_libs.push(wrapper_file);
@@ -392,7 +384,7 @@ fn link_rlib<'a>(
         codegen_results.crate_info.used_libraries.iter(),
         tmpdir.as_ref(),
         true,
-    )? {
+    ) {
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
             sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
@@ -433,7 +425,7 @@ fn link_rlib<'a>(
         ab.add_file(&lib)
     }
 
-    Ok(ab)
+    ab
 }
 
 /// Extract all symbols defined in raw-dylib libraries, collated by library name.
@@ -445,7 +437,7 @@ fn link_rlib<'a>(
 fn collate_raw_dylibs<'a>(
     sess: &Session,
     used_libraries: impl IntoIterator<Item = &'a NativeLib>,
-) -> Result<Vec<(String, Vec<DllImport>)>, ErrorGuaranteed> {
+) -> Vec<(String, Vec<DllImport>)> {
     // Use index maps to preserve original order of imports and libraries.
     let mut dylib_table = FxIndexMap::<String, FxIndexMap<Symbol, &DllImport>>::default();
 
@@ -469,15 +461,13 @@ fn collate_raw_dylibs<'a>(
             }
         }
     }
-    if let Some(guar) = sess.dcx().has_errors() {
-        return Err(guar);
-    }
-    Ok(dylib_table
+    sess.dcx().abort_if_errors();
+    dylib_table
         .into_iter()
         .map(|(name, imports)| {
             (name, imports.into_iter().map(|(_, import)| import.clone()).collect())
         })
-        .collect())
+        .collect()
 }
 
 fn create_dll_import_libs<'a>(
@@ -486,8 +476,8 @@ fn create_dll_import_libs<'a>(
     used_libraries: impl IntoIterator<Item = &'a NativeLib>,
     tmpdir: &Path,
     is_direct_dependency: bool,
-) -> Result<Vec<PathBuf>, ErrorGuaranteed> {
-    Ok(collate_raw_dylibs(sess, used_libraries)?
+) -> Vec<PathBuf> {
+    collate_raw_dylibs(sess, used_libraries)
         .into_iter()
         .map(|(raw_dylib_name, raw_dylib_imports)| {
             let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" };
@@ -537,7 +527,7 @@ fn create_dll_import_libs<'a>(
 
             output_path
         })
-        .collect())
+        .collect()
 }
 
 /// Create a static archive.
@@ -557,7 +547,7 @@ fn link_staticlib(
     codegen_results: &CodegenResults,
     out_filename: &Path,
     tempdir: &MaybeTempDir,
-) -> Result<(), ErrorGuaranteed> {
+) {
     info!("preparing staticlib to {:?}", out_filename);
     let mut ab = link_rlib(
         sess,
@@ -565,7 +555,7 @@ fn link_staticlib(
         codegen_results,
         RlibFlavor::StaticlibBase,
         tempdir,
-    )?;
+    );
     let mut all_native_libs = vec![];
 
     let res = each_linked_rlib(
@@ -628,13 +618,12 @@ fn link_staticlib(
     let fmts = codegen_results
         .crate_info
         .dependency_formats
-        .iter()
-        .find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None })
+        .get(&CrateType::Staticlib)
         .expect("no dependency formats for staticlib");
 
     let mut all_rust_dylibs = vec![];
     for &cnum in crates {
-        match fmts.get(cnum.as_usize() - 1) {
+        match fmts.get(cnum) {
             Some(&Linkage::Dynamic) => {}
             _ => continue,
         }
@@ -656,8 +645,6 @@ fn link_staticlib(
             print_native_static_libs(sess, &print.out, &all_native_libs, &all_rust_dylibs);
         }
     }
-
-    Ok(())
 }
 
 /// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
@@ -773,7 +760,7 @@ fn link_natively(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     tmpdir: &Path,
-) -> Result<(), ErrorGuaranteed> {
+) {
     info!("preparing {:?} to {:?}", crate_type, out_filename);
     let (linker_path, flavor) = linker_and_flavor(sess);
     let self_contained_components = self_contained_components(sess, crate_type);
@@ -797,7 +784,7 @@ fn link_natively(
         temp_filename,
         codegen_results,
         self_contained_components,
-    )?;
+    );
 
     linker::disable_localization(&mut cmd);
 
@@ -998,12 +985,12 @@ fn link_natively(
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
                 let escaped_output = escape_linker_output(&output, flavor);
-                // FIXME: Add UI tests for this error.
                 let err = errors::LinkingFailed {
                     linker_path: &linker_path,
                     exit_status: prog.status,
-                    command: &cmd,
+                    command: cmd,
                     escaped_output,
+                    verbose: sess.opts.verbose,
                 };
                 sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
@@ -1047,22 +1034,22 @@ fn link_natively(
         Err(e) => {
             let linker_not_found = e.kind() == io::ErrorKind::NotFound;
 
-            if linker_not_found {
-                sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e });
+            let err = if linker_not_found {
+                sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e })
             } else {
                 sess.dcx().emit_err(errors::UnableToExeLinker {
                     linker_path,
                     error: e,
                     command_formatted: format!("{cmd:?}"),
-                });
-            }
+                })
+            };
 
             if sess.target.is_like_msvc && linker_not_found {
                 sess.dcx().emit_note(errors::MsvcMissingLinker);
                 sess.dcx().emit_note(errors::CheckInstalledVisualStudio);
                 sess.dcx().emit_note(errors::InsufficientVSCodeProduct);
             }
-            FatalError.raise();
+            err.raise_fatal();
         }
     }
 
@@ -1113,14 +1100,14 @@ fn link_natively(
         let stripcmd = "rust-objcopy";
         match (strip, crate_type) {
             (Strip::Debuginfo, _) => {
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-S"])
+                strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
             }
             // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
             (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"])
+                strip_with_external_utility(sess, stripcmd, out_filename, &["-x"])
             }
             (Strip::Symbols, _) => {
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[])
+                strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
             }
             (Strip::None, _) => {}
         }
@@ -1136,9 +1123,7 @@ fn link_natively(
         let stripcmd = if !sess.host.is_like_solaris { "rust-objcopy" } else { "/usr/bin/strip" };
         match strip {
             // Always preserve the symbol table (-x).
-            Strip::Debuginfo => {
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &["-x"])
-            }
+            Strip::Debuginfo => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
             // Strip::Symbols is handled via the --strip-all linker option.
             Strip::Symbols => {}
             Strip::None => {}
@@ -1154,15 +1139,11 @@ fn link_natively(
         match strip {
             Strip::Debuginfo => {
                 // FIXME: AIX's strip utility only offers option to strip line number information.
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[
-                    "-X32_64", "-l",
-                ])
+                strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"])
             }
             Strip::Symbols => {
                 // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
-                strip_symbols_with_external_utility(sess, stripcmd, out_filename, &[
-                    "-X32_64", "-r",
-                ])
+                strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"])
             }
             Strip::None => {}
         }
@@ -1173,16 +1154,9 @@ fn link_natively(
         ab.add_file(temp_filename);
         ab.build(out_filename);
     }
-
-    Ok(())
 }
 
-fn strip_symbols_with_external_utility(
-    sess: &Session,
-    util: &str,
-    out_filename: &Path,
-    options: &[&str],
-) {
+fn strip_with_external_utility(sess: &Session, util: &str, out_filename: &Path, options: &[&str]) {
     let mut cmd = Command::new(util);
     cmd.args(options);
 
@@ -2228,7 +2202,7 @@ fn linker_with_args(
     out_filename: &Path,
     codegen_results: &CodegenResults,
     self_contained_components: LinkSelfContainedComponents,
-) -> Result<Command, ErrorGuaranteed> {
+) -> Command {
     let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled();
     let cmd = &mut *super::linker::get_linker(
         sess,
@@ -2352,18 +2326,17 @@ fn linker_with_args(
         codegen_results.crate_info.used_libraries.iter(),
         tmpdir,
         true,
-    )? {
+    ) {
         cmd.add_object(&output_path);
     }
     // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case
     // they are used within inlined functions or instantiated generic functions. We do this *after*
     // handling the raw-dylib symbols in the current crate to make sure that those are chosen first
     // by the linker.
-    let (_, dependency_linkage) = codegen_results
+    let dependency_linkage = codegen_results
         .crate_info
         .dependency_formats
-        .iter()
-        .find(|(ty, _)| *ty == crate_type)
+        .get(&crate_type)
         .expect("failed to find crate type in dependency format list");
 
     // We sort the libraries below
@@ -2372,8 +2345,8 @@ fn linker_with_args(
         .crate_info
         .native_libraries
         .iter()
-        .filter_map(|(cnum, libraries)| {
-            (dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then_some(libraries)
+        .filter_map(|(&cnum, libraries)| {
+            (dependency_linkage[cnum] != Linkage::Static).then_some(libraries)
         })
         .flatten()
         .collect::<Vec<_>>();
@@ -2384,7 +2357,7 @@ fn linker_with_args(
         native_libraries_from_nonstatics,
         tmpdir,
         false,
-    )? {
+    ) {
         cmd.add_object(&output_path);
     }
 
@@ -2431,7 +2404,7 @@ fn linker_with_args(
     // to it and remove the option. Currently the last holdout is wasm32-unknown-emscripten.
     add_post_link_args(cmd, sess, flavor);
 
-    Ok(cmd.take_cmd())
+    cmd.take_cmd()
 }
 
 fn add_order_independent_options(
@@ -2742,13 +2715,21 @@ fn add_upstream_rust_crates(
     // Linking to a rlib involves just passing it to the linker (the linker
     // will slurp up the object files inside), and linking to a dynamic library
     // involves just passing the right -l flag.
-    let (_, data) = codegen_results
+    let data = codegen_results
         .crate_info
         .dependency_formats
-        .iter()
-        .find(|(ty, _)| *ty == crate_type)
+        .get(&crate_type)
         .expect("failed to find crate type in dependency format list");
 
+    if sess.target.is_like_aix {
+        // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override
+        // the dependency name when outputing a shared library. Thus, `ld` will
+        // use the full path to shared libraries as the dependency if passed it
+        // by default unless `noipath` is passed.
+        // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command.
+        cmd.link_or_cc_arg("-bnoipath");
+    }
+
     for &cnum in &codegen_results.crate_info.used_crates {
         // We may not pass all crates through to the linker. Some crates may appear statically in
         // an existing dylib, meaning we'll pick up all the symbols from the dylib.
@@ -2757,7 +2738,7 @@ fn add_upstream_rust_crates(
         // (e.g. `libstd` when `-C prefer-dynamic` is used).
         // FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some
         // reason, it shouldn't do that because `profiler_builtins` should indeed be linked.
-        let linkage = data[cnum.as_usize() - 1];
+        let linkage = data[cnum];
         let link_static_crate = linkage == Linkage::Static
             || (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
                 && (codegen_results.crate_info.compiler_builtins == Some(cnum)
@@ -2985,7 +2966,7 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
 
 fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {
     match lib.cfg {
-        Some(ref cfg) => rustc_attr::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
+        Some(ref cfg) => rustc_attr_parsing::cfg_matches(cfg, sess, CRATE_NODE_ID, None),
         None => true,
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 17323f67ffa..8fb831471a9 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -16,7 +16,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo, S
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
-use rustc_span::symbol::sym;
+use rustc_span::sym;
 use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
 use tracing::{debug, warn};
 
@@ -1693,6 +1693,8 @@ impl<'a> Linker for AixLinker<'a> {
 
     fn pgo_gen(&mut self) {
         self.link_arg("-bdbg:namedsects:ss");
+        self.link_arg("-u");
+        self.link_arg("__llvm_profile_runtime");
     }
 
     fn control_flow_guard(&mut self) {}
@@ -1741,15 +1743,10 @@ fn for_each_exported_symbols_include_dep<'tcx>(
     crate_type: CrateType,
     mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
 ) {
-    for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() {
-        callback(symbol, info, LOCAL_CRATE);
-    }
-
     let formats = tcx.dependency_formats(());
-    let deps = formats.iter().find_map(|(t, list)| (*t == crate_type).then_some(list)).unwrap();
+    let deps = &formats[&crate_type];
 
-    for (index, dep_format) in deps.iter().enumerate() {
-        let cnum = CrateNum::new(index + 1);
+    for (cnum, dep_format) in deps.iter_enumerated() {
         // For each dependency that we are linking to statically ...
         if *dep_format == Linkage::Static {
             for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
diff --git a/compiler/rustc_codegen_ssa/src/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs
index ab8b06a05fc..efccf7687a1 100644
--- a/compiler/rustc_codegen_ssa/src/back/lto.rs
+++ b/compiler/rustc_codegen_ssa/src/back/lto.rs
@@ -1,11 +1,14 @@
 use std::ffi::CString;
 use std::sync::Arc;
 
+use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_data_structures::memmap::Mmap;
 use rustc_errors::FatalError;
+use rustc_middle::ty::TyCtxt;
 
 use super::write::CodegenContext;
 use crate::ModuleCodegen;
+use crate::back::write::ModuleConfig;
 use crate::traits::*;
 
 pub struct ThinModule<B: WriteBackendMethods> {
@@ -81,6 +84,24 @@ impl<B: WriteBackendMethods> LtoModuleCodegen<B> {
             LtoModuleCodegen::Thin(ref m) => m.cost(),
         }
     }
+
+    /// Run autodiff on Fat LTO module
+    pub unsafe fn autodiff(
+        self,
+        cgcx: &CodegenContext<B>,
+        tcx: TyCtxt<'_>,
+        diff_fncs: Vec<AutoDiffItem>,
+        config: &ModuleConfig,
+    ) -> Result<LtoModuleCodegen<B>, FatalError> {
+        match &self {
+            LtoModuleCodegen::Fat(module) => {
+                B::autodiff(cgcx, tcx, &module, diff_fncs, config)?;
+            }
+            _ => panic!("autodiff called with non-fat LTO module"),
+        }
+
+        Ok(self)
+    }
 }
 
 pub enum SerializedModule<M: ModuleBufferMethods> {
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 788a8a13b3e..60ab2919352 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -311,7 +311,8 @@ fn exported_symbols_provider_local(
             }
 
             if !tcx.sess.opts.share_generics() {
-                if tcx.codegen_fn_attrs(mono_item.def_id()).inline == rustc_attr::InlineAttr::Never
+                if tcx.codegen_fn_attrs(mono_item.def_id()).inline
+                    == rustc_attr_parsing::InlineAttr::Never
                 {
                     // this is OK, we explicitly allow sharing inline(never) across crates even
                     // without share-generics.
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 7c0e9cfd5a7..b40bb4ed5d2 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -6,9 +6,9 @@ use std::sync::Arc;
 use std::sync::mpsc::{Receiver, Sender, channel};
 use std::{fs, io, mem, str, thread};
 
-use jobserver::{Acquired, Client};
 use rustc_ast::attr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_data_structures::jobserver::{self, Acquired};
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
 use rustc_errors::emitter::Emitter;
@@ -33,8 +33,7 @@ use rustc_session::config::{
     self, CrateType, Lto, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath,
 };
 use rustc_span::source_map::SourceMap;
-use rustc_span::symbol::sym;
-use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
+use rustc_span::{FileName, InnerSpan, Span, SpanData, sym};
 use rustc_target::spec::{MergeFunctions, SanitizerSet};
 use tracing::debug;
 
@@ -456,7 +455,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
     metadata_module: Option<CompiledModule>,
 ) -> OngoingCodegen<B> {
     let (coordinator_send, coordinator_receive) = channel();
-    let sess = tcx.sess;
 
     let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
     let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
@@ -477,7 +475,6 @@ pub(crate) fn start_async_codegen<B: ExtraBackendMethods>(
         shared_emitter,
         codegen_worker_send,
         coordinator_receive,
-        sess.jobserver.clone(),
         Arc::new(regular_config),
         Arc::new(metadata_config),
         Arc::new(allocator_config),
@@ -1093,7 +1090,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
     shared_emitter: SharedEmitter,
     codegen_worker_send: Sender<CguMessage>,
     coordinator_receive: Receiver<Box<dyn Any + Send>>,
-    jobserver: Client,
     regular_config: Arc<ModuleConfig>,
     metadata_config: Arc<ModuleConfig>,
     allocator_config: Arc<ModuleConfig>,
@@ -1145,7 +1141,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
     // get tokens on `coordinator_receive` which will
     // get managed in the main loop below.
     let coordinator_send2 = coordinator_send.clone();
-    let helper = jobserver
+    let helper = jobserver::client()
         .into_helper_thread(move |token| {
             drop(coordinator_send2.send(Box::new(Message::Token::<B>(token))));
         })
@@ -1837,7 +1833,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>(
 
 enum SharedEmitterMessage {
     Diagnostic(Diagnostic),
-    InlineAsmError(u32, String, Level, Option<(String, Vec<InnerSpan>)>),
+    InlineAsmError(SpanData, String, Level, Option<(String, Vec<InnerSpan>)>),
     Fatal(String),
 }
 
@@ -1859,12 +1855,12 @@ impl SharedEmitter {
 
     pub fn inline_asm_error(
         &self,
-        cookie: u32,
+        span: SpanData,
         msg: String,
         level: Level,
         source: Option<(String, Vec<InnerSpan>)>,
     ) {
-        drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)));
+        drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source)));
     }
 
     fn fatal(&self, msg: &str) {
@@ -1883,7 +1879,11 @@ impl Translate for SharedEmitter {
 }
 
 impl Emitter for SharedEmitter {
-    fn emit_diagnostic(&mut self, mut diag: rustc_errors::DiagInner) {
+    fn emit_diagnostic(
+        &mut self,
+        mut diag: rustc_errors::DiagInner,
+        _registry: &rustc_errors::registry::Registry,
+    ) {
         // Check that we aren't missing anything interesting when converting to
         // the cut-down local `DiagInner`.
         assert_eq!(diag.span, MultiSpan::new());
@@ -1949,17 +1949,12 @@ impl SharedEmitterMain {
                     dcx.emit_diagnostic(d);
                     sess.dcx().abort_if_errors();
                 }
-                Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
+                Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => {
                     assert_matches!(level, Level::Error | Level::Warning | Level::Note);
-                    let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
                     let mut err = Diag::<()>::new(sess.dcx(), level, msg);
-
-                    // If the cookie is 0 then we don't have span information.
-                    if cookie != 0 {
-                        let pos = BytePos::from_u32(cookie);
-                        let span = Span::with_root_ctxt(pos, pos);
-                        err.span(span);
-                    };
+                    if !span.is_dummy() {
+                        err.span(span.span());
+                    }
 
                     // Point to the generated assembly if it is available.
                     if let Some((buffer, spans)) = source {
@@ -2028,8 +2023,6 @@ pub struct OngoingCodegen<B: ExtraBackendMethods> {
 
 impl<B: ExtraBackendMethods> OngoingCodegen<B> {
     pub fn join(self, sess: &Session) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>) {
-        let _timer = sess.timer("finish_ongoing_codegen");
-
         self.shared_emitter_main.check(sess, true);
         let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 27c9cb0b31e..77e1fed720d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -5,7 +5,6 @@ use std::time::{Duration, Instant};
 use itertools::Itertools;
 use rustc_abi::FIRST_VARIANT;
 use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
-use rustc_attr as attr;
 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::{Lrc, par_map};
@@ -25,12 +24,12 @@ use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType};
-use rustc_span::symbol::sym;
-use rustc_span::{DUMMY_SP, Symbol};
+use rustc_span::{DUMMY_SP, Symbol, sym};
 use rustc_trait_selection::infer::at::ToTrace;
 use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 use tracing::{debug, info};
+use {rustc_ast as ast, rustc_attr_parsing as attr};
 
 use crate::assert_module_sources::CguReuse;
 use crate::back::link::are_upstream_rust_objects_already_included;
@@ -873,7 +872,8 @@ impl CrateInfo {
             crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect();
         let local_crate_name = tcx.crate_name(LOCAL_CRATE);
         let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
-        let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
+        let subsystem =
+            ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
         let windows_subsystem = subsystem.map(|subsystem| {
             if subsystem != sym::windows && subsystem != sym::console {
                 tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index a5acd8170ab..cdb72aba36f 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -1,13 +1,13 @@
-use rustc_ast::{MetaItemInner, MetaItemKind, ast, attr};
-use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_name};
+use rustc_ast::attr::list_contains_name;
+use rustc_ast::{MetaItemInner, attr};
+use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
-use rustc_hir::{LangItem, lang_items};
+use rustc_hir::{self as hir, HirId, LangItem, lang_items};
 use rustc_middle::middle::codegen_fn_attrs::{
     CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
 };
@@ -16,8 +16,7 @@ use rustc_middle::query::Providers;
 use rustc_middle::ty::{self as ty, TyCtxt};
 use rustc_session::parse::feature_err;
 use rustc_session::{Session, lint};
-use rustc_span::symbol::Ident;
-use rustc_span::{Span, sym};
+use rustc_span::{Ident, Span, sym};
 use rustc_target::spec::{SanitizerSet, abi};
 
 use crate::errors;
@@ -78,6 +77,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     let mut inline_span = None;
     let mut link_ordinal_span = None;
     let mut no_sanitize_span = None;
+    let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
 
     for attr in attrs.iter() {
         // In some cases, attribute are only valid on functions, but it's the `check_attr`
@@ -116,7 +116,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
             sym::no_mangle => {
                 if tcx.opt_item_name(did.to_def_id()).is_some() {
-                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
+                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+                    mixed_export_name_no_mangle_lint_state.track_no_mangle(
+                        attr.span,
+                        tcx.local_def_id_to_hir_id(did),
+                        attr,
+                    );
                 } else {
                     tcx.dcx()
                         .struct_span_err(
@@ -240,12 +245,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         .emit();
                     }
                     codegen_fn_attrs.export_name = Some(s);
+                    mixed_export_name_no_mangle_lint_state.track_export_name(attr.span);
                 }
             }
             sym::target_feature => {
                 if !tcx.is_closure_like(did.to_def_id())
                     && let Some(fn_sig) = fn_sig()
-                    && fn_sig.skip_binder().safety() == hir::Safety::Safe
+                    && fn_sig.skip_binder().safety().is_safe()
                 {
                     if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                         // The `#[target_feature]` attribute is allowed on
@@ -419,7 +425,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     && let [item] = items.as_slice()
                     && let Some((sym::align, literal)) = item.singleton_lit_list()
                 {
-                    rustc_attr::parse_alignment(&literal.kind)
+                    rustc_attr_parsing::parse_alignment(&literal.kind)
                         .map_err(|msg| {
                             struct_span_code_err!(
                                 tcx.dcx(),
@@ -513,61 +519,65 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
     }
 
+    mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
+
     codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
         if !attr.has_name(sym::inline) {
             return ia;
         }
-        match attr.meta_kind() {
-            Some(MetaItemKind::Word) => InlineAttr::Hint,
-            Some(MetaItemKind::List(ref items)) => {
-                inline_span = Some(attr.span);
-                if items.len() != 1 {
-                    struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument")
-                        .emit();
-                    InlineAttr::None
-                } else if list_contains_name(items, sym::always) {
-                    InlineAttr::Always
-                } else if list_contains_name(items, sym::never) {
-                    InlineAttr::Never
-                } else {
-                    struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
-                        .with_help("valid inline arguments are `always` and `never`")
-                        .emit();
+        if attr.is_word() {
+            InlineAttr::Hint
+        } else if let Some(ref items) = attr.meta_item_list() {
+            inline_span = Some(attr.span);
+            if items.len() != 1 {
+                struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit();
+                InlineAttr::None
+            } else if list_contains_name(items, sym::always) {
+                InlineAttr::Always
+            } else if list_contains_name(items, sym::never) {
+                InlineAttr::Never
+            } else {
+                struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
+                    .with_help("valid inline arguments are `always` and `never`")
+                    .emit();
 
-                    InlineAttr::None
-                }
+                InlineAttr::None
             }
-            Some(MetaItemKind::NameValue(_)) => ia,
-            None => ia,
+        } else {
+            ia
         }
     });
 
+    // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
+    // but not for the code generation backend because at that point the naked function will just be
+    // a declaration, with a definition provided in global assembly.
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+        codegen_fn_attrs.inline = InlineAttr::Never;
+    }
+
     codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
         let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
-        match attr.meta_kind() {
-            Some(MetaItemKind::Word) => {
+        if attr.is_word() {
+            err(attr.span, "expected one argument");
+            ia
+        } else if let Some(ref items) = attr.meta_item_list() {
+            inline_span = Some(attr.span);
+            if items.len() != 1 {
                 err(attr.span, "expected one argument");
-                ia
-            }
-            Some(MetaItemKind::List(ref items)) => {
-                inline_span = Some(attr.span);
-                if items.len() != 1 {
-                    err(attr.span, "expected one argument");
-                    OptimizeAttr::None
-                } else if list_contains_name(items, sym::size) {
-                    OptimizeAttr::Size
-                } else if list_contains_name(items, sym::speed) {
-                    OptimizeAttr::Speed
-                } else {
-                    err(items[0].span(), "invalid argument");
-                    OptimizeAttr::None
-                }
+                OptimizeAttr::None
+            } else if list_contains_name(items, sym::size) {
+                OptimizeAttr::Size
+            } else if list_contains_name(items, sym::speed) {
+                OptimizeAttr::Speed
+            } else {
+                err(items[0].span(), "invalid argument");
+                OptimizeAttr::None
             }
-            Some(MetaItemKind::NameValue(_)) => ia,
-            None => ia,
+        } else {
+            OptimizeAttr::None
         }
     });
 
@@ -626,10 +636,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
     }
 
-    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
-        codegen_fn_attrs.inline = InlineAttr::Never;
-    }
-
     // Weak lang items have the same semantics as "std internal" symbols in the
     // sense that they're preserved through all our LTO passes and only
     // strippable by the linker.
@@ -719,7 +725,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     false
 }
 
-fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
+fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
     let meta_item_list = attr.meta_item_list();
     let meta_item_list = meta_item_list.as_deref();
@@ -779,6 +785,49 @@ fn check_link_name_xor_ordinal(
     }
 }
 
+#[derive(Default)]
+struct MixedExportNameAndNoMangleState<'a> {
+    export_name: Option<Span>,
+    hir_id: Option<HirId>,
+    no_mangle: Option<Span>,
+    no_mangle_attr: Option<&'a hir::Attribute>,
+}
+
+impl<'a> MixedExportNameAndNoMangleState<'a> {
+    fn track_export_name(&mut self, span: Span) {
+        self.export_name = Some(span);
+    }
+
+    fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a hir::Attribute) {
+        self.no_mangle = Some(span);
+        self.hir_id = Some(hir_id);
+        self.no_mangle_attr = Some(attr_name);
+    }
+
+    /// Emit diagnostics if the lint condition is met.
+    fn lint_if_mixed(self, tcx: TyCtxt<'_>) {
+        if let Self {
+            export_name: Some(export_name),
+            no_mangle: Some(no_mangle),
+            hir_id: Some(hir_id),
+            no_mangle_attr: Some(no_mangle_attr),
+        } = self
+        {
+            tcx.emit_node_span_lint(
+                lint::builtin::UNUSED_ATTRIBUTES,
+                hir_id,
+                no_mangle,
+                errors::MixedExportNameAndNoMangle {
+                    no_mangle,
+                    no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr),
+                    export_name,
+                    removal_span: no_mangle,
+                },
+            );
+        }
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers };
 }
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
index 88d36b19da4..7c62c03d574 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
@@ -65,8 +65,8 @@ fn tag_base_type_opt<'tcx>(
     });
 
     match enum_type_and_layout.layout.variants() {
-        // A single-variant enum has no discriminant.
-        Variants::Single { .. } => None,
+        // A single-variant or no-variant enum has no discriminant.
+        Variants::Single { .. } | Variants::Empty => None,
 
         Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
             // Niche tags are always normalized to unsized integers of the correct size.
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 6c4f6d37972..869798d8be1 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -432,11 +432,9 @@ fn push_debuginfo_type_name<'tcx>(
                 push_closure_or_coroutine_name(tcx, def_id, args, qualified, output, visited);
             }
         }
-        // Type parameters from polymorphized functions.
-        ty::Param(_) => {
-            write!(output, "{t:?}").unwrap();
-        }
-        ty::Error(_)
+        ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binders)"),
+        ty::Param(_)
+        | ty::Error(_)
         | ty::Infer(_)
         | ty::Placeholder(..)
         | ty::Alias(..)
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index f93cb52ea3e..c7213bbc801 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1,6 +1,7 @@
 //! Errors emitted by codegen_ssa
 
 use std::borrow::Cow;
+use std::ffi::OsString;
 use std::io::Error;
 use std::num::ParseIntError;
 use std::path::{Path, PathBuf};
@@ -10,7 +11,7 @@ use rustc_errors::codes::*;
 use rustc_errors::{
     Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level,
 };
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::LayoutError;
 use rustc_span::{Span, Symbol};
@@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper {
 }
 
 pub(crate) struct LinkingFailed<'a> {
-    pub linker_path: &'a PathBuf,
+    pub linker_path: &'a Path,
     pub exit_status: ExitStatus,
-    pub command: &'a Command,
+    pub command: Command,
     pub escaped_output: String,
+    pub verbose: bool,
 }
 
 impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> {
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+    fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
         let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed);
         diag.arg("linker_path", format!("{}", self.linker_path.display()));
         diag.arg("exit_status", format!("{}", self.exit_status));
 
         let contains_undefined_ref = self.escaped_output.contains("undefined reference to");
 
-        diag.note(format!("{:?}", self.command)).note(self.escaped_output);
+        if self.verbose {
+            diag.note(format!("{:?}", self.command));
+        } else {
+            enum ArgGroup {
+                Regular(OsString),
+                Objects(usize),
+                Rlibs(PathBuf, Vec<OsString>),
+            }
+
+            // Omit rust object files and fold rlibs in the error by default to make linker errors a
+            // bit less verbose.
+            let orig_args = self.command.take_args();
+            let mut args: Vec<ArgGroup> = vec![];
+            for arg in orig_args {
+                if arg.as_encoded_bytes().ends_with(b".rcgu.o") {
+                    if let Some(ArgGroup::Objects(n)) = args.last_mut() {
+                        *n += 1;
+                    } else {
+                        args.push(ArgGroup::Objects(1));
+                    }
+                } else if arg.as_encoded_bytes().ends_with(b".rlib") {
+                    let rlib_path = Path::new(&arg);
+                    let dir = rlib_path.parent().unwrap();
+                    let filename = rlib_path.file_name().unwrap().to_owned();
+                    if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() {
+                        if parent == dir {
+                            rlibs.push(filename);
+                        } else {
+                            args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                        }
+                    } else {
+                        args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename]));
+                    }
+                } else {
+                    args.push(ArgGroup::Regular(arg));
+                }
+            }
+            self.command.args(args.into_iter().map(|arg_group| match arg_group {
+                ArgGroup::Regular(arg) => arg,
+                ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")),
+                ArgGroup::Rlibs(dir, rlibs) => {
+                    let mut arg = dir.into_os_string();
+                    arg.push("/{");
+                    let mut first = true;
+                    for rlib in rlibs {
+                        if !first {
+                            arg.push(",");
+                        }
+                        first = false;
+                        arg.push(rlib);
+                    }
+                    arg.push("}");
+                    arg
+                }
+            }));
+
+            diag.note(format!("{:?}", self.command));
+            diag.note("some arguments are omitted. use `--verbose` to show all linker arguments");
+        }
+
+        diag.note(self.escaped_output);
 
         // Trying to match an error from OS linkers
         // which by now we have no way to translate.
@@ -1114,3 +1176,15 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_
 #[derive(Diagnostic)]
 #[diag(codegen_ssa_aix_strip_not_used)]
 pub(crate) struct AixStripNotUsed;
+
+#[derive(LintDiagnostic)]
+#[diag(codegen_ssa_mixed_export_name_and_no_mangle)]
+pub(crate) struct MixedExportNameAndNoMangle {
+    #[label]
+    pub no_mangle: Span,
+    pub no_mangle_attr: String,
+    #[note]
+    pub export_name: Span,
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
+    pub removal_span: Span,
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 7dc8ab38a97..65c6067c740 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -42,7 +42,7 @@ use rustc_session::Session;
 use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
 use rustc_session::cstore::{self, CrateSource};
 use rustc_session::utils::NativeLibKind;
-use rustc_span::symbol::Symbol;
+use rustc_span::Symbol;
 
 pub mod assert_module_sources;
 pub mod back;
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index e3ed12b5ce6..b0a1dedd646 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -847,10 +847,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
         let (instance, mut llfn) = match *callee.layout.ty.kind() {
             ty::FnDef(def_id, args) => (
-                Some(
-                    ty::Instance::expect_resolve(bx.tcx(), bx.typing_env(), def_id, args, fn_span)
-                        .polymorphize(bx.tcx()),
-                ),
+                Some(ty::Instance::expect_resolve(
+                    bx.tcx(),
+                    bx.typing_env(),
+                    def_id,
+                    args,
+                    fn_span,
+                )),
                 None,
             ),
             ty::FnPtr(..) => (None, Some(callee.immediate())),
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index d4d7f16db55..843a996d2bf 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -10,8 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{Instance, Ty};
 use rustc_middle::{bug, mir, ty};
 use rustc_session::config::DebugInfo;
-use rustc_span::symbol::{Symbol, kw};
-use rustc_span::{BytePos, Span, hygiene};
+use rustc_span::{BytePos, Span, Symbol, hygiene, kw};
 
 use super::operand::{OperandRef, OperandValue};
 use super::place::{PlaceRef, PlaceValue};
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 299b98c0a4f..304ac4544ee 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // If we're swapping something that's *not* an `OperandValue::Ref`,
         // then we can do it directly and avoid the alloca.
         // Otherwise, we'll let the fallback MIR body take care of it.
-        if let sym::typed_swap = name {
+        if let sym::typed_swap_nonoverlapping = name {
             let pointee_ty = fn_args.type_at(0);
             let pointee_layout = bx.layout_of(pointee_ty);
             if !bx.is_backend_ref(pointee_layout)
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 0cbc5c45736..62f69af3f2f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -20,6 +20,7 @@ mod coverageinfo;
 pub mod debuginfo;
 mod intrinsic;
 mod locals;
+mod naked_asm;
 pub mod operand;
 pub mod place;
 mod rvalue;
@@ -176,6 +177,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
     debug!("fn_abi: {:?}", fn_abi);
 
+    if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
+        crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
+        return;
+    }
+
     let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir);
 
     let start_llbb = Bx::append_block(cx, llfn, "start");
diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
new file mode 100644
index 00000000000..cac3cc587cb
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
@@ -0,0 +1,266 @@
+use rustc_attr_parsing::InstructionSetAttr;
+use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility};
+use rustc_middle::mir::{Body, InlineAsmOperand};
+use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
+use rustc_middle::ty::{Instance, TyCtxt};
+use rustc_middle::{bug, ty};
+use rustc_span::sym;
+
+use crate::common;
+use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};
+
+pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    cx: &'a Bx::CodegenCx,
+    mir: &Body<'tcx>,
+    instance: Instance<'tcx>,
+) {
+    let rustc_middle::mir::TerminatorKind::InlineAsm {
+        asm_macro: _,
+        template,
+        ref operands,
+        options,
+        line_spans,
+        targets: _,
+        unwind: _,
+    } = mir.basic_blocks.iter().next().unwrap().terminator().kind
+    else {
+        bug!("#[naked] functions should always terminate with an asm! block")
+    };
+
+    let operands: Vec<_> =
+        operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect();
+
+    let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
+    let name = cx.mangled_name(instance);
+    let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data);
+
+    let mut template_vec = Vec::new();
+    template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
+    template_vec.extend(template.iter().cloned());
+    template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into()));
+
+    cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
+}
+
+fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    cx: &'a Bx::CodegenCx,
+    instance: Instance<'tcx>,
+    op: &InlineAsmOperand<'tcx>,
+) -> GlobalAsmOperandRef<'tcx> {
+    match op {
+        InlineAsmOperand::Const { value } => {
+            let const_value = instance
+                .instantiate_mir_and_normalize_erasing_regions(
+                    cx.tcx(),
+                    cx.typing_env(),
+                    ty::EarlyBinder::bind(value.const_),
+                )
+                .eval(cx.tcx(), cx.typing_env(), value.span)
+                .expect("erroneous constant missed by mono item collection");
+
+            let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
+                cx.tcx(),
+                cx.typing_env(),
+                ty::EarlyBinder::bind(value.ty()),
+            );
+
+            let string = common::asm_const_to_str(
+                cx.tcx(),
+                value.span,
+                const_value,
+                cx.layout_of(mono_type),
+            );
+
+            GlobalAsmOperandRef::Const { string }
+        }
+        InlineAsmOperand::SymFn { value } => {
+            let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
+                cx.tcx(),
+                cx.typing_env(),
+                ty::EarlyBinder::bind(value.ty()),
+            );
+
+            let instance = match mono_type.kind() {
+                &ty::FnDef(def_id, args) => Instance::new(def_id, args),
+                _ => bug!("asm sym is not a function"),
+            };
+
+            GlobalAsmOperandRef::SymFn { instance }
+        }
+        InlineAsmOperand::SymStatic { def_id } => {
+            GlobalAsmOperandRef::SymStatic { def_id: *def_id }
+        }
+        InlineAsmOperand::In { .. }
+        | InlineAsmOperand::Out { .. }
+        | InlineAsmOperand::InOut { .. }
+        | InlineAsmOperand::Label { .. } => {
+            bug!("invalid operand type for naked_asm!")
+        }
+    }
+}
+
+enum AsmBinaryFormat {
+    Elf,
+    Macho,
+    Coff,
+}
+
+impl AsmBinaryFormat {
+    fn from_target(target: &rustc_target::spec::Target) -> Self {
+        if target.is_like_windows {
+            Self::Coff
+        } else if target.is_like_osx {
+            Self::Macho
+        } else {
+            Self::Elf
+        }
+    }
+}
+
+fn prefix_and_suffix<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    instance: Instance<'tcx>,
+    asm_name: &str,
+    item_data: &MonoItemData,
+) -> (String, String) {
+    use std::fmt::Write;
+
+    let asm_binary_format = AsmBinaryFormat::from_target(&tcx.sess.target);
+
+    let is_arm = tcx.sess.target.arch == "arm";
+    let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode);
+
+    let attrs = tcx.codegen_fn_attrs(instance.def_id());
+    let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
+    let align = attrs.alignment.map(|a| a.bytes()).unwrap_or(4);
+
+    // See https://sourceware.org/binutils/docs/as/ARM-Directives.html for info on these directives.
+    // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`.
+    let (arch_prefix, arch_suffix) = if is_arm {
+        (
+            match attrs.instruction_set {
+                None => match is_thumb {
+                    true => ".thumb\n.thumb_func",
+                    false => ".arm",
+                },
+                Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func",
+                Some(InstructionSetAttr::ArmA32) => ".arm",
+            },
+            match is_thumb {
+                true => ".thumb",
+                false => ".arm",
+            },
+        )
+    } else {
+        ("", "")
+    };
+
+    let emit_fatal = |msg| tcx.dcx().span_fatal(tcx.def_span(instance.def_id()), msg);
+
+    // see https://godbolt.org/z/cPK4sxKor.
+    let write_linkage = |w: &mut String| -> std::fmt::Result {
+        match item_data.linkage {
+            Linkage::External => {
+                writeln!(w, ".globl {asm_name}")?;
+            }
+            Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => {
+                match asm_binary_format {
+                    AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => {
+                        writeln!(w, ".weak {asm_name}")?;
+                    }
+                    AsmBinaryFormat::Macho => {
+                        writeln!(w, ".globl {asm_name}")?;
+                        writeln!(w, ".weak_definition {asm_name}")?;
+                    }
+                }
+            }
+            Linkage::Internal | Linkage::Private => {
+                // write nothing
+            }
+            Linkage::Appending => emit_fatal("Only global variables can have appending linkage!"),
+            Linkage::Common => emit_fatal("Functions may not have common linkage"),
+            Linkage::AvailableExternally => {
+                // this would make the function equal an extern definition
+                emit_fatal("Functions may not have available_externally linkage")
+            }
+            Linkage::ExternalWeak => {
+                // FIXME: actually this causes a SIGILL in LLVM
+                emit_fatal("Functions may not have external weak linkage")
+            }
+        }
+
+        Ok(())
+    };
+
+    let mut begin = String::new();
+    let mut end = String::new();
+    match asm_binary_format {
+        AsmBinaryFormat::Elf => {
+            let section = link_section.unwrap_or(format!(".text.{asm_name}"));
+
+            let progbits = match is_arm {
+                true => "%progbits",
+                false => "@progbits",
+            };
+
+            let function = match is_arm {
+                true => "%function",
+                false => "@function",
+            };
+
+            writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
+            writeln!(begin, ".balign {align}").unwrap();
+            write_linkage(&mut begin).unwrap();
+            if let Visibility::Hidden = item_data.visibility {
+                writeln!(begin, ".hidden {asm_name}").unwrap();
+            }
+            writeln!(begin, ".type {asm_name}, {function}").unwrap();
+            if !arch_prefix.is_empty() {
+                writeln!(begin, "{}", arch_prefix).unwrap();
+            }
+            writeln!(begin, "{asm_name}:").unwrap();
+
+            writeln!(end).unwrap();
+            writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap();
+            writeln!(end, ".popsection").unwrap();
+            if !arch_suffix.is_empty() {
+                writeln!(end, "{}", arch_suffix).unwrap();
+            }
+        }
+        AsmBinaryFormat::Macho => {
+            let section = link_section.unwrap_or("__TEXT,__text".to_string());
+            writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
+            writeln!(begin, ".balign {align}").unwrap();
+            write_linkage(&mut begin).unwrap();
+            if let Visibility::Hidden = item_data.visibility {
+                writeln!(begin, ".private_extern {asm_name}").unwrap();
+            }
+            writeln!(begin, "{asm_name}:").unwrap();
+
+            writeln!(end).unwrap();
+            writeln!(end, ".popsection").unwrap();
+            if !arch_suffix.is_empty() {
+                writeln!(end, "{}", arch_suffix).unwrap();
+            }
+        }
+        AsmBinaryFormat::Coff => {
+            let section = link_section.unwrap_or(format!(".text.{asm_name}"));
+            writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
+            writeln!(begin, ".balign {align}").unwrap();
+            write_linkage(&mut begin).unwrap();
+            writeln!(begin, ".def {asm_name}").unwrap();
+            writeln!(begin, ".scl 2").unwrap();
+            writeln!(begin, ".type 32").unwrap();
+            writeln!(begin, ".endef {asm_name}").unwrap();
+            writeln!(begin, "{asm_name}:").unwrap();
+
+            writeln!(end).unwrap();
+            writeln!(end, ".popsection").unwrap();
+            if !arch_suffix.is_empty() {
+                writeln!(end, "{}", arch_suffix).unwrap();
+            }
+        }
+    }
+
+    (begin, end)
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index c38484109d2..c634f864ffb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -243,6 +243,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
             return bx.cx().const_poison(cast_to);
         }
         let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
+            Variants::Empty => unreachable!("we already handled uninhabited types"),
             Variants::Single { index } => {
                 let discr_val = self
                     .layout
@@ -365,9 +366,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
             return;
         }
         match self.layout.variants {
-            Variants::Single { index } => {
-                assert_eq!(index, variant_index);
-            }
+            Variants::Empty => unreachable!("we already handled uninhabited types"),
+            Variants::Single { index } => assert_eq!(index, variant_index),
+
             Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
                 let ptr = self.project_field(bx, tag_field);
                 let to =
@@ -422,10 +423,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
             layout.size
         };
 
-        let llval = bx.inbounds_gep(bx.cx().backend_type(self.layout), self.val.llval, &[
-            bx.cx().const_usize(0),
-            llindex,
-        ]);
+        let llval = bx.inbounds_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]);
         let align = self.val.align.restrict_for_offset(offset);
         PlaceValue::new_sized(llval, align).with_type(layout)
     }
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index f63b2d139c5..3b62148abb7 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -10,9 +10,9 @@ use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, Span};
 use tracing::{debug, instrument};
 
+use super::FunctionCx;
 use super::operand::{OperandRef, OperandValue};
 use super::place::PlaceRef;
-use super::{FunctionCx, LocalRef};
 use crate::common::IntPredicate;
 use crate::traits::*;
 use crate::{MemFlags, base};
@@ -478,8 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     def_id,
                                     args,
                                 )
-                                .unwrap()
-                                .polymorphize(bx.cx().tcx());
+                                .unwrap();
                                 OperandValue::Immediate(bx.get_fn_addr(instance))
                             }
                             _ => bug!("{} cannot be reified to a fn ptr", operand.layout.ty),
@@ -493,8 +492,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                                     def_id,
                                     args,
                                     ty::ClosureKind::FnOnce,
-                                )
-                                .polymorphize(bx.cx().tcx());
+                                );
                                 OperandValue::Immediate(bx.cx().get_fn_addr(instance))
                             }
                             _ => bug!("{} cannot be cast to a fn ptr", operand.layout.ty),
@@ -595,14 +593,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 self.codegen_place_to_pointer(bx, place, mk_ptr)
             }
 
-            mir::Rvalue::Len(place) => {
-                let size = self.evaluate_array_len(bx, place);
-                OperandRef {
-                    val: OperandValue::Immediate(size),
-                    layout: bx.cx().layout_of(bx.tcx().types.usize),
-                }
-            }
-
             mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
                 if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
             {
@@ -802,24 +792,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         }
     }
 
-    fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value {
-        // ZST are passed as operands and require special handling
-        // because codegen_place() panics if Local is operand.
-        if let Some(index) = place.as_local() {
-            if let LocalRef::Operand(op) = self.locals[index] {
-                if let ty::Array(_, n) = op.layout.ty.kind() {
-                    let n = n
-                        .try_to_target_usize(bx.tcx())
-                        .expect("expected monomorphic const in codegen");
-                    return bx.cx().const_usize(n);
-                }
-            }
-        }
-        // use common size calculation for non zero-sized types
-        let cg_value = self.codegen_place(bx, place.as_ref());
-        cg_value.len(bx.cx())
-    }
-
     /// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref`
     fn codegen_place_to_pointer(
         &mut self,
@@ -1091,7 +1063,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::Rvalue::Ref(..) |
             mir::Rvalue::CopyForDeref(..) |
             mir::Rvalue::RawPtr(..) |
-            mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 038c5857fac..6749bc63327 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -1,4 +1,5 @@
 use rustc_hir as hir;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility};
 use rustc_middle::ty::Instance;
@@ -135,7 +136,13 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
                 cx.predefine_static(def_id, linkage, visibility, symbol_name);
             }
             MonoItem::Fn(instance) => {
-                cx.predefine_fn(instance, linkage, visibility, symbol_name);
+                let attrs = cx.tcx().codegen_fn_attrs(instance.def_id());
+
+                if attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
+                    // do not define this function; it will become a global assembly block
+                } else {
+                    cx.predefine_fn(instance, linkage, visibility, symbol_name);
+                };
             }
             MonoItem::GlobalAsm(..) => {}
         }
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index eee7cc75400..7e80d014ea2 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,17 +1,16 @@
-use rustc_ast::ast;
-use rustc_attr::InstructionSetAttr;
+use rustc_attr_parsing::InstructionSetAttr;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Applicability;
+use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
-use rustc_span::Span;
-use rustc_span::symbol::{Symbol, sym};
-use rustc_target::target_features::{self, Stability};
+use rustc_span::{Span, Symbol, sym};
+use rustc_target::target_features;
 
 use crate::errors;
 
@@ -19,8 +18,8 @@ use crate::errors;
 /// Enabled target features are added to `target_features`.
 pub(crate) fn from_target_feature_attr(
     tcx: TyCtxt<'_>,
-    attr: &ast::Attribute,
-    rust_target_features: &UnordMap<String, target_features::Stability>,
+    attr: &hir::Attribute,
+    rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
     target_features: &mut Vec<TargetFeature>,
 ) {
     let Some(list) = attr.meta_item_list() else { return };
@@ -63,32 +62,24 @@ pub(crate) fn from_target_feature_attr(
                 return None;
             };
 
-            // Only allow target features whose feature gates have been enabled.
-            let allowed = match stability {
-                Stability::Forbidden { .. } => false,
-                Stability::Stable => true,
-                Stability::Unstable(name) => rust_features.enabled(*name),
-            };
-            if !allowed {
-                match stability {
-                    Stability::Stable => unreachable!(),
-                    &Stability::Unstable(lang_feature_name) => {
-                        feature_err(
-                            &tcx.sess,
-                            lang_feature_name,
-                            item.span(),
-                            format!("the target feature `{feature}` is currently unstable"),
-                        )
-                        .emit();
-                    }
-                    Stability::Forbidden { reason } => {
-                        tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
-                            span: item.span(),
-                            feature,
-                            reason,
-                        });
-                    }
-                }
+            // Only allow target features whose feature gates have been enabled
+            // and which are permitted to be toggled.
+            if let Err(reason) = stability.toggle_allowed(/*enable*/ true) {
+                tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
+                    span: item.span(),
+                    feature,
+                    reason,
+                });
+            } else if let Some(nightly_feature) = stability.requires_nightly()
+                && !rust_features.enabled(nightly_feature)
+            {
+                feature_err(
+                    &tcx.sess,
+                    nightly_feature,
+                    item.span(),
+                    format!("the target feature `{feature}` is currently unstable"),
+                )
+                .emit();
             }
             Some(Symbol::intern(feature))
         }));
@@ -156,18 +147,19 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         rust_target_features: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
+            let target = &tcx.sess.target;
             if tcx.sess.opts.actually_rustdoc {
                 // rustdoc needs to be able to document functions that use all the features, so
                 // whitelist them all
                 rustc_target::target_features::all_rust_features()
-                    .map(|(a, b)| (a.to_string(), b))
+                    .map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
                     .collect()
             } else {
                 tcx.sess
                     .target
                     .rust_target_features()
                     .iter()
-                    .map(|&(a, b, _)| (a.to_string(), b))
+                    .map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
                     .collect()
             }
         },
diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs
index f4853da1156..7767bffbfbf 100644
--- a/compiler/rustc_codegen_ssa/src/traits/asm.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs
@@ -68,4 +68,11 @@ pub trait AsmCodegenMethods<'tcx> {
         options: InlineAsmOptions,
         line_spans: &[Span],
     );
+
+    /// The mangled name of this instance
+    ///
+    /// Additional mangling is used on
+    /// some targets to add a leading underscore (Mach-O)
+    /// or byte count suffixes (x86 Windows).
+    fn mangled_name(&self, instance: Instance<'tcx>) -> String;
 }
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 7eab889edf0..ebcf118b903 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -4,7 +4,6 @@ use std::hash::Hash;
 use rustc_ast::expand::allocator::AllocatorKind;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{DynSend, DynSync};
-use rustc_errors::ErrorGuaranteed;
 use rustc_metadata::EncodedMetadata;
 use rustc_metadata::creader::MetadataLoaderDyn;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@@ -12,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
 use rustc_middle::util::Providers;
 use rustc_session::Session;
 use rustc_session::config::{self, OutputFilenames, PrintRequest};
-use rustc_span::symbol::Symbol;
+use rustc_span::Symbol;
 
 use super::CodegenObject;
 use super::write::WriteBackendMethods;
@@ -46,7 +45,9 @@ pub trait CodegenBackend {
 
     fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
 
-    fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
+    /// Returns the features that should be set in `cfg(target_features)`.
+    /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
+    fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
         vec![]
     }
 
@@ -84,13 +85,8 @@ pub trait CodegenBackend {
     ) -> (CodegenResults, FxIndexMap<WorkProductId, WorkProduct>);
 
     /// This is called on the returned [`CodegenResults`] from [`join_codegen`](Self::join_codegen).
-    fn link(
-        &self,
-        sess: &Session,
-        codegen_results: CodegenResults,
-        outputs: &OutputFilenames,
-    ) -> Result<(), ErrorGuaranteed> {
-        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs)
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) {
+        link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, outputs);
     }
 
     /// Returns `true` if this backend can be safely called from multiple threads.
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index b0138ac8bfe..3ee13b19f66 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -382,7 +382,7 @@ pub trait BuilderMethods<'a, 'tcx>:
     /// Avoids `alloca`s for Immediates and ScalarPairs.
     ///
     /// FIXME: Maybe do something smarter for Ref types too?
-    /// For now, the `typed_swap` intrinsic just doesn't call this for those
+    /// For now, the `typed_swap_nonoverlapping` intrinsic just doesn't call this for those
     /// cases (in non-debug), preferring the fallback body instead.
     fn typed_place_swap(
         &mut self,
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index aabe9e33c4a..51e2255efe1 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -1,5 +1,7 @@
+use rustc_ast::expand::autodiff_attrs::AutoDiffItem;
 use rustc_errors::{DiagCtxtHandle, FatalError};
 use rustc_middle::dep_graph::WorkProduct;
+use rustc_middle::ty::TyCtxt;
 
 use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
@@ -61,6 +63,13 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
         want_summary: bool,
     ) -> (String, Self::ThinBuffer);
     fn serialize_module(module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer);
+    fn autodiff(
+        cgcx: &CodegenContext<Self>,
+        tcx: TyCtxt<'_>,
+        module: &ModuleCodegen<Self::Module>,
+        diff_fncs: Vec<AutoDiffItem>,
+        config: &ModuleConfig,
+    ) -> Result<(), FatalError>;
 }
 
 pub trait ThinBufferMethods: Send + Sync {