about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs24
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl3
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs43
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs2
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs20
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs10
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml1
-rw-r--r--compiler/rustc_driver_impl/messages.ftl4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs80
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs23
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0391.md3
-rw-r--r--compiler/rustc_error_messages/src/lib.rs7
-rw-r--r--compiler/rustc_errors/src/emitter.rs2
-rw-r--r--compiler/rustc_errors/src/json/tests.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs31
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs2
-rw-r--r--compiler/rustc_expand/src/tests.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/lint.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs4
-rw-r--r--compiler/rustc_interface/src/interface.rs11
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_interface/src/util.rs2
-rw-r--r--compiler/rustc_metadata/src/foreign_modules.rs17
-rw-r--r--compiler/rustc_metadata/src/locator.rs49
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs80
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs34
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs6
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs2
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs10
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs3
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs2
-rw-r--r--compiler/rustc_parse_format/src/lib.rs103
-rw-r--r--compiler/rustc_parse_format/src/tests.rs15
-rw-r--r--compiler/rustc_query_system/messages.ftl1
-rw-r--r--compiler/rustc_query_system/src/error.rs2
-rw-r--r--compiler/rustc_query_system/src/query/job.rs46
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs10
-rw-r--r--compiler/rustc_resolve/src/ident.rs4
-rw-r--r--compiler/rustc_session/src/cstore.rs2
-rw-r--r--compiler/rustc_session/src/parse.rs13
-rw-r--r--compiler/rustc_session/src/session.rs18
-rw-r--r--compiler/rustc_span/src/edition.rs6
-rw-r--r--compiler/rustc_span/src/lib.rs16
57 files changed, 511 insertions, 282 deletions
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 429e62c4a1c..9e193402feb 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1619,13 +1619,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 debug!(?hir_bounds);
 
                 let lifetime_mapping = if in_trait {
-                    self.arena.alloc_from_iter(
-                        collected_lifetime_mapping
-                            .iter()
-                            .map(|(lifetime, def_id)| (**lifetime, *def_id)),
+                    Some(
+                        &*self.arena.alloc_from_iter(
+                            collected_lifetime_mapping
+                                .iter()
+                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
+                        ),
                     )
                 } else {
-                    &mut []
+                    None
                 };
 
                 let opaque_ty_item = hir::OpaqueTy {
@@ -2090,13 +2092,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params);
 
                 let lifetime_mapping = if in_trait {
-                    self.arena.alloc_from_iter(
-                        collected_lifetime_mapping
-                            .iter()
-                            .map(|(lifetime, def_id)| (**lifetime, *def_id)),
+                    Some(
+                        &*self.arena.alloc_from_iter(
+                            collected_lifetime_mapping
+                                .iter()
+                                .map(|(lifetime, def_id)| (**lifetime, *def_id)),
+                        ),
                     )
                 } else {
-                    &mut []
+                    None
                 };
 
                 let opaque_ty_item = hir::OpaqueTy {
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index de1622951fe..aed4a8f3c85 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,7 +1,8 @@
 codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
 
 codegen_llvm_dlltool_fail_import_library =
-    Dlltool could not create import library: {$stdout}
+    Dlltool could not create import library with {$dlltool_path} {$dlltool_args}:
+    {$stdout}
     {$stderr}
 
 codegen_llvm_dynamic_linking_with_lto =
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 39275272e42..4c69b9503a2 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -335,6 +335,10 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     to_add.extend(probestack_attr(cx));
     to_add.extend(stackprotector_attr(cx));
 
+    if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_BUILTINS) {
+        to_add.push(llvm::CreateAttrString(cx.llcx, "no-builtins"));
+    }
+
     if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
         to_add.push(AttributeKind::Cold.create_attr(cx.llcx));
     }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index a6416e9540c..10bf954d242 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -198,25 +198,24 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 "arm" => ("arm", "--32"),
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
-            let result = std::process::Command::new(&dlltool)
-                .args([
-                    "-d",
-                    def_file_path.to_str().unwrap(),
-                    "-D",
-                    lib_name,
-                    "-l",
-                    output_path.to_str().unwrap(),
-                    "-m",
-                    dlltool_target_arch,
-                    "-f",
-                    dlltool_target_bitness,
-                    "--no-leading-underscore",
-                    "--temp-prefix",
-                    temp_prefix.to_str().unwrap(),
-                ])
-                .output();
-
-            match result {
+            let mut dlltool_cmd = std::process::Command::new(&dlltool);
+            dlltool_cmd.args([
+                "-d",
+                def_file_path.to_str().unwrap(),
+                "-D",
+                lib_name,
+                "-l",
+                output_path.to_str().unwrap(),
+                "-m",
+                dlltool_target_arch,
+                "-f",
+                dlltool_target_bitness,
+                "--no-leading-underscore",
+                "--temp-prefix",
+                temp_prefix.to_str().unwrap(),
+            ]);
+
+            match dlltool_cmd.output() {
                 Err(e) => {
                     sess.emit_fatal(ErrorCallingDllTool {
                         dlltool_path: dlltool.to_string_lossy(),
@@ -226,6 +225,12 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
                 // dlltool returns '0' on failure, so check for error output instead.
                 Ok(output) if !output.stderr.is_empty() => {
                     sess.emit_fatal(DlltoolFailImportLibrary {
+                        dlltool_path: dlltool.to_string_lossy(),
+                        dlltool_args: dlltool_cmd
+                            .get_args()
+                            .map(|arg| arg.to_string_lossy())
+                            .collect::<Vec<_>>()
+                            .join(" "),
                         stdout: String::from_utf8_lossy(&output.stdout),
                         stderr: String::from_utf8_lossy(&output.stderr),
                     })
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index 44869ced1ae..fced6d504d2 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -81,6 +81,8 @@ pub(crate) struct ErrorCallingDllTool<'a> {
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_dlltool_fail_import_library)]
 pub(crate) struct DlltoolFailImportLibrary<'a> {
+    pub dlltool_path: Cow<'a, str>,
+    pub dlltool_args: String,
     pub stdout: Cow<'a, str>,
     pub stderr: Cow<'a, str>,
 }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index 984efa21044..6582fd62387 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -17,7 +17,6 @@ tempfile = "3.2"
 thorin-dwp = "0.6"
 pathdiff = "0.2.0"
 serde_json = "1.0.59"
-snap = "1"
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 regex = "1.4"
 
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index e8b8665e39d..c4bb51edade 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -10,8 +10,6 @@ use object::{
     ObjectSymbol, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
 };
 
-use snap::write::FrameEncoder;
-
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
 use rustc_metadata::fs::METADATA_FILENAME;
@@ -481,19 +479,15 @@ pub fn create_compressed_metadata_file(
     metadata: &EncodedMetadata,
     symbol_name: &str,
 ) -> Vec<u8> {
-    let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
-    // Our length will be backfilled once we're done writing
-    compressed.write_all(&[0; 4]).unwrap();
-    FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
-    let meta_len = rustc_metadata::METADATA_HEADER.len();
-    let data_len = (compressed.len() - meta_len - 4) as u32;
-    compressed[meta_len..meta_len + 4].copy_from_slice(&data_len.to_be_bytes());
+    let mut packed_metadata = rustc_metadata::METADATA_HEADER.to_vec();
+    packed_metadata.write_all(&(metadata.raw_data().len() as u32).to_be_bytes()).unwrap();
+    packed_metadata.extend(metadata.raw_data());
 
     let Some(mut file) = create_object_file(sess) else {
-        return compressed.to_vec();
+        return packed_metadata.to_vec();
     };
     if file.format() == BinaryFormat::Xcoff {
-        return create_compressed_metadata_file_for_xcoff(file, &compressed, symbol_name);
+        return create_compressed_metadata_file_for_xcoff(file, &packed_metadata, symbol_name);
     }
     let section = file.add_section(
         file.segment_name(StandardSegment::Data).to_vec(),
@@ -507,14 +501,14 @@ pub fn create_compressed_metadata_file(
         }
         _ => {}
     };
-    let offset = file.append_section_data(section, &compressed, 1);
+    let offset = file.append_section_data(section, &packed_metadata, 1);
 
     // For MachO and probably PE this is necessary to prevent the linker from throwing away the
     // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
     file.add_symbol(Symbol {
         name: symbol_name.as_bytes().to_vec(),
         value: offset,
-        size: compressed.len() as u64,
+        size: packed_metadata.len() as u64,
         kind: SymbolKind::Data,
         scope: SymbolScope::Dynamic,
         weak: false,
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index ececa29b231..1c5d7a7c68e 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -362,7 +362,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
 
 impl<B: WriteBackendMethods> CodegenContext<B> {
     pub fn create_diag_handler(&self) -> Handler {
-        Handler::with_emitter(true, None, Box::new(self.diag_emitter.clone()))
+        Handler::with_emitter(true, None, Box::new(self.diag_emitter.clone()), None)
     }
 
     pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index d6c23012762..0c7b8a79612 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -1,4 +1,4 @@
-use rustc_ast::{ast, MetaItemKind, NestedMetaItem};
+use rustc_ast::{ast, attr, MetaItemKind, NestedMetaItem};
 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -60,6 +60,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
     }
 
+    // When `no_builtins` is applied at the crate level, we should add the
+    // `no-builtins` attribute to each function to ensure it takes effect in LTO.
+    let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID);
+    let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
+    if no_builtins {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
+    }
+
     let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
 
     let mut inline_span = None;
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 67352c55c90..a7b01618ade 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2021"
 [lib]
 
 [dependencies]
+time = { version = "0.3", default-features = false, features = ["formatting", ] }
 tracing = { version = "0.1.35" }
 serde_json = "1.0.59"
 rustc_log = { path = "../rustc_log" }
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 22b4ec6b0d1..9b2f2c33860 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -3,7 +3,11 @@ driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
 driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
 
 driver_impl_ice_flags = compiler flags: {$flags}
+driver_impl_ice_path = please attach the file at `{$path}` to your bug report
+driver_impl_ice_path_error = the ICE couldn't be written to `{$path}`: {$error}
+driver_impl_ice_path_error_env = the environment variable `RUSTC_ICE` is set to `{$env_var}`
 driver_impl_ice_version = rustc {$version} running on {$triple}
+
 driver_impl_rlink_empty_version_number = The input does not contain version number
 
 driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 25c043149e8..11303e7d09e 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -7,6 +7,8 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(lazy_cell)]
 #![feature(decl_macro)]
+#![feature(ice_to_disk)]
+#![feature(let_chains)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -57,8 +59,11 @@ use std::panic::{self, catch_unwind};
 use std::path::PathBuf;
 use std::process::{self, Command, Stdio};
 use std::str;
+use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::OnceLock;
-use std::time::Instant;
+use std::time::{Instant, SystemTime};
+use time::format_description::well_known::Rfc3339;
+use time::OffsetDateTime;
 
 #[allow(unused_macros)]
 macro do_not_use_print($($t:tt)*) {
@@ -294,6 +299,7 @@ fn run_compiler(
         input: Input::File(PathBuf::new()),
         output_file: ofile,
         output_dir: odir,
+        ice_file: ice_path().clone(),
         file_loader,
         locale_resources: DEFAULT_LOCALE_RESOURCES,
         lint_caps: Default::default(),
@@ -1292,9 +1298,29 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
     }
 }
 
-/// Stores the default panic hook, from before [`install_ice_hook`] was called.
-static DEFAULT_HOOK: OnceLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
-    OnceLock::new();
+pub static ICE_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
+
+pub fn ice_path() -> &'static Option<PathBuf> {
+    ICE_PATH.get_or_init(|| {
+        if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
+            return None;
+        }
+        if let Ok("0") = std::env::var("RUST_BACKTRACE").as_deref() {
+            return None;
+        }
+        let mut path = match std::env::var("RUSTC_ICE").as_deref() {
+            // Explicitly opting out of writing ICEs to disk.
+            Ok("0") => return None,
+            Ok(s) => PathBuf::from(s),
+            Err(_) => std::env::current_dir().unwrap_or_default(),
+        };
+        let now: OffsetDateTime = SystemTime::now().into();
+        let file_now = now.format(&Rfc3339).unwrap_or(String::new());
+        let pid = std::process::id();
+        path.push(format!("rustc-ice-{file_now}-{pid}.txt"));
+        Some(path)
+    })
+}
 
 /// Installs a panic hook that will print the ICE message on unexpected panics.
 ///
@@ -1318,8 +1344,6 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
         std::env::set_var("RUST_BACKTRACE", "full");
     }
 
-    let default_hook = DEFAULT_HOOK.get_or_init(panic::take_hook);
-
     panic::set_hook(Box::new(move |info| {
         // If the error was caused by a broken pipe then this is not a bug.
         // Write the error and return immediately. See #98700.
@@ -1336,7 +1360,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
         // Invoke the default handler, which prints the actual panic message and optionally a backtrace
         // Don't do this for delayed bugs, which already emit their own more useful backtrace.
         if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
-            (*default_hook)(info);
+            std::panic_hook_with_disk_dump(info, ice_path().as_deref());
 
             // Separate the output with an empty line
             eprintln!();
@@ -1368,7 +1392,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
         false,
         TerminalUrl::No,
     ));
-    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
+    let handler = rustc_errors::Handler::with_emitter(true, None, emitter, None);
 
     // a .span_bug or .bug call has already printed what
     // it wants to print.
@@ -1379,10 +1403,40 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
     }
 
     handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
-    handler.emit_note(session_diagnostics::IceVersion {
-        version: util::version_str!().unwrap_or("unknown_version"),
-        triple: config::host_triple(),
-    });
+
+    let version = util::version_str!().unwrap_or("unknown_version");
+    let triple = config::host_triple();
+
+    static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
+
+    let file = if let Some(path) = ice_path().as_ref() {
+        // Create the ICE dump target file.
+        match crate::fs::File::options().create(true).append(true).open(&path) {
+            Ok(mut file) => {
+                handler
+                    .emit_note(session_diagnostics::IcePath { path: path.display().to_string() });
+                if FIRST_PANIC.swap(false, Ordering::SeqCst) {
+                    let _ = write!(file, "\n\nrustc version: {version}\nplatform: {triple}");
+                }
+                Some(file)
+            }
+            Err(err) => {
+                // The path ICE couldn't be written to disk, provide feedback to the user as to why.
+                handler.emit_warning(session_diagnostics::IcePathError {
+                    path: path.display().to_string(),
+                    error: err.to_string(),
+                    env_var: std::env::var("RUSTC_ICE")
+                        .ok()
+                        .map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }),
+                });
+                handler.emit_note(session_diagnostics::IceVersion { version, triple });
+                None
+            }
+        }
+    } else {
+        handler.emit_note(session_diagnostics::IceVersion { version, triple });
+        None
+    };
 
     if let Some((flags, excluded_cargo_defaults)) = extra_compiler_flags() {
         handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
@@ -1396,7 +1450,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info:
 
     let num_frames = if backtrace { None } else { Some(2) };
 
-    interface::try_print_query_stack(&handler, num_frames);
+    interface::try_print_query_stack(&handler, num_frames, file);
 
     // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
     // printed all the relevant info.
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 638b368f702..f7f06b7d0f2 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -1,4 +1,4 @@
-use rustc_macros::Diagnostic;
+use rustc_macros::{Diagnostic, Subdiagnostic};
 
 #[derive(Diagnostic)]
 #[diag(driver_impl_rlink_unable_to_read)]
@@ -57,6 +57,27 @@ pub(crate) struct IceVersion<'a> {
 }
 
 #[derive(Diagnostic)]
+#[diag(driver_impl_ice_path)]
+pub(crate) struct IcePath {
+    pub path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(driver_impl_ice_path_error)]
+pub(crate) struct IcePathError {
+    pub path: String,
+    pub error: String,
+    #[subdiagnostic]
+    pub env_var: Option<IcePathErrorEnv>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(driver_impl_ice_path_error_env)]
+pub(crate) struct IcePathErrorEnv {
+    pub env_var: String,
+}
+
+#[derive(Diagnostic)]
 #[diag(driver_impl_ice_flags)]
 pub(crate) struct IceFlags {
     pub flags: String,
diff --git a/compiler/rustc_error_codes/src/error_codes/E0391.md b/compiler/rustc_error_codes/src/error_codes/E0391.md
index dff50ccaa0b..457fbd002a1 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0391.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0391.md
@@ -14,3 +14,6 @@ trait SecondTrait : FirstTrait {
 
 The previous example contains a circular dependency between two traits:
 `FirstTrait` depends on `SecondTrait` which itself depends on `FirstTrait`.
+
+See https://rustc-dev-guide.rust-lang.org/overview.html#queries and
+https://rustc-dev-guide.rust-lang.org/query.html for more information.
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 51e1fe531dd..1879ece59e3 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -354,6 +354,13 @@ impl DiagnosticMessage {
             }
         }
     }
+
+    pub fn as_str(&self) -> Option<&str> {
+        match self {
+            DiagnosticMessage::Eager(s) | DiagnosticMessage::Str(s) => Some(s),
+            DiagnosticMessage::FluentIdentifier(_, _) => None,
+        }
+    }
 }
 
 impl From<String> for DiagnosticMessage {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 9d4d159fd96..a0fa4115c3e 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -1982,7 +1982,7 @@ impl EmitterWriter {
                 // We special case `#[derive(_)]\n` and other attribute suggestions, because those
                 // are the ones where context is most useful.
                 let file_lines = sm
-                    .span_to_lines(span.primary_span().unwrap().shrink_to_hi())
+                    .span_to_lines(parts[0].span.shrink_to_hi())
                     .expect("span_to_lines failed when emitting suggestion");
                 let line_num = sm.lookup_char_pos(parts[0].span.lo()).line;
                 if let Some(line) = file_lines.file.get_line(line_num - 1) {
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 671dc449eaa..db0dd4ffe8e 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -64,7 +64,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
-        let handler = Handler::with_emitter(true, None, Box::new(je));
+        let handler = Handler::with_emitter(true, None, Box::new(je), None);
         handler.span_err(span, "foo");
 
         let bytes = output.lock().unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b9db25103a3..31410c39d36 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -47,9 +47,10 @@ use std::borrow::Cow;
 use std::error::Report;
 use std::fmt;
 use std::hash::Hash;
+use std::io::Write;
 use std::num::NonZeroUsize;
 use std::panic;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
 use termcolor::{Color, ColorSpec};
 
@@ -461,6 +462,10 @@ struct HandlerInner {
     ///
     /// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
     fulfilled_expectations: FxHashSet<LintExpectationId>,
+
+    /// The file where the ICE information is stored. This allows delayed_span_bug backtraces to be
+    /// stored along side the main panic backtrace.
+    ice_file: Option<PathBuf>,
 }
 
 /// A key denoting where from a diagnostic was stashed.
@@ -550,6 +555,7 @@ impl Handler {
         sm: Option<Lrc<SourceMap>>,
         fluent_bundle: Option<Lrc<FluentBundle>>,
         fallback_bundle: LazyFallbackBundle,
+        ice_file: Option<PathBuf>,
     ) -> Self {
         Self::with_tty_emitter_and_flags(
             color_config,
@@ -557,6 +563,7 @@ impl Handler {
             fluent_bundle,
             fallback_bundle,
             HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
+            ice_file,
         )
     }
 
@@ -566,6 +573,7 @@ impl Handler {
         fluent_bundle: Option<Lrc<FluentBundle>>,
         fallback_bundle: LazyFallbackBundle,
         flags: HandlerFlags,
+        ice_file: Option<PathBuf>,
     ) -> Self {
         let emitter = Box::new(EmitterWriter::stderr(
             color_config,
@@ -579,23 +587,26 @@ impl Handler {
             flags.track_diagnostics,
             TerminalUrl::No,
         ));
-        Self::with_emitter_and_flags(emitter, flags)
+        Self::with_emitter_and_flags(emitter, flags, ice_file)
     }
 
     pub fn with_emitter(
         can_emit_warnings: bool,
         treat_err_as_bug: Option<NonZeroUsize>,
         emitter: Box<dyn Emitter + sync::Send>,
+        ice_file: Option<PathBuf>,
     ) -> Self {
         Handler::with_emitter_and_flags(
             emitter,
             HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
+            ice_file,
         )
     }
 
     pub fn with_emitter_and_flags(
         emitter: Box<dyn Emitter + sync::Send>,
         flags: HandlerFlags,
+        ice_file: Option<PathBuf>,
     ) -> Self {
         Self {
             flags,
@@ -618,6 +629,7 @@ impl Handler {
                 check_unstable_expect_diagnostics: false,
                 unstable_expect_diagnostics: Vec::new(),
                 fulfilled_expectations: Default::default(),
+                ice_file,
             }),
         }
     }
@@ -1657,8 +1669,21 @@ impl HandlerInner {
         explanation: impl Into<DiagnosticMessage> + Copy,
     ) {
         let mut no_bugs = true;
+        // If backtraces are enabled, also print the query stack
+        let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0");
         for bug in bugs {
-            let mut bug = bug.decorate();
+            if let Some(file) = self.ice_file.as_ref()
+                && let Ok(mut out) = std::fs::File::options().append(true).open(file)
+            {
+                let _ = write!(
+                    &mut out,
+                    "\n\ndelayed span bug: {}\n{}",
+                    bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(),
+                    &bug.note
+                );
+            }
+            let mut bug =
+                if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
 
             if no_bugs {
                 // Put the overall explanation before the `DelayedBug`s, to
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 42cc0a6b143..102bae2a744 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -1200,7 +1200,7 @@ fn check_matcher_core<'tt>(
                             err.span_label(sp, format!("not allowed after `{}` fragments", kind));
 
                             if kind == NonterminalKind::PatWithOr
-                                && sess.edition.rust_2021()
+                                && sess.edition.at_least_rust_2021()
                                 && next_token.is_token(&BinOp(token::BinOpToken::Or))
                             {
                                 let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl(
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 8a5e09475ff..6490e52955d 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -161,7 +161,7 @@ fn test_harness(file_text: &str, span_labels: Vec<SpanLabel>, expected_output: &
             false,
             TerminalUrl::No,
         );
-        let handler = Handler::with_emitter(true, None, Box::new(emitter));
+        let handler = Handler::with_emitter(true, None, Box::new(emitter), None);
         #[allow(rustc::untranslatable_diagnostic)]
         handler.span_err(msp, "foo");
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 35ef30114b7..68f1559ea22 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2664,10 +2664,19 @@ pub struct OpaqueTy<'hir> {
     pub generics: &'hir Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
     pub origin: OpaqueTyOrigin,
-    // Opaques have duplicated lifetimes, this mapping connects the original lifetime with the copy
-    // so we can later generate bidirectional outlives predicates to enforce that these lifetimes
-    // stay in sync.
-    pub lifetime_mapping: &'hir [(Lifetime, LocalDefId)],
+    /// Return-position impl traits (and async futures) must "reify" any late-bound
+    /// lifetimes that are captured from the function signature they originate from.
+    ///
+    /// This is done by generating a new early-bound lifetime parameter local to the
+    /// opaque which is substituted in the function signature with the late-bound
+    /// lifetime.
+    ///
+    /// This mapping associated a captured lifetime (first parameter) with the new
+    /// early-bound lifetime that was generated for the opaque.
+    pub lifetime_mapping: Option<&'hir [(Lifetime, LocalDefId)]>,
+    /// Whether the opaque is a return-position impl trait (or async future)
+    /// originating from a trait method. This makes it so that the opaque is
+    /// lowered as an associated type.
     pub in_trait: bool,
 }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index 05a3ab63d5c..ff55174f97a 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -86,7 +86,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 ));
             }
 
-            if self_ty.span.edition().rust_2021() {
+            if self_ty.span.edition().at_least_rust_2021() {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
                 let mut diag =
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 1c9070600db..979b101e7fe 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -66,7 +66,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
             let opaque_ty_id = tcx.hir().local_def_id_to_hir_id(opaque_def_id.expect_local());
             let opaque_ty_node = tcx.hir().get(opaque_ty_id);
             let Node::Item(&Item {
-                kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping, .. }),
+                kind: ItemKind::OpaqueTy(OpaqueTy { lifetime_mapping: Some(lifetime_mapping), .. }),
                 ..
             }) = opaque_ty_node
             else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index bd7e7a671e6..94f64a1ffdb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -860,7 +860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
             .and_then(|r| {
                 // lint bare trait if the method is found in the trait
-                if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+                if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
                     diag.emit();
                 }
                 Ok(r)
@@ -890,7 +890,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 // emit or cancel the diagnostic for bare traits
-                if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+                if span.edition().at_least_rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
                     if trait_missing_method {
                         // cancel the diag for bare traits when meeting `MyTrait::missing_method`
                         diag.cancel();
@@ -908,7 +908,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         error,
                         None,
                         Expectation::NoExpectation,
-                        trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
+                        trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021
                     ) {
                         e.emit();
                     }
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index ec4e7f7f88a..4efe95c4dc5 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -32,7 +32,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         );
 
         // Rust 2021 and later is already using the new prelude
-        if span.rust_2021() {
+        if span.at_least_rust_2021() {
             return;
         }
 
@@ -203,7 +203,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pick: &Pick<'tcx>,
     ) {
         // Rust 2021 and later is already using the new prelude
-        if span.rust_2021() {
+        if span.at_least_rust_2021() {
             return;
         }
 
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 9ef97243c5e..05eed1923d1 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -437,7 +437,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // this case used to be allowed by the compiler,
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
-                if self.tcx.sess.rust_2018() {
+                if self.tcx.sess.at_least_rust_2018() {
                     self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
                 } else {
                     self.tcx.struct_span_lint_hir(
@@ -1592,7 +1592,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     if let Some(method_name) = self.method_name {
                         // Some trait methods are excluded for arrays before 2021.
                         // (`array.into_iter()` wants a slice iterator for compatibility.)
-                        if self_ty.is_array() && !method_name.span.rust_2021() {
+                        if self_ty.is_array() && !method_name.span.at_least_rust_2021() {
                             let trait_def = self.tcx.trait_def(trait_ref.def_id);
                             if trait_def.skip_array_during_method_dispatch {
                                 return ProbeResult::NoMatch;
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index f77a4d16b5f..fb81a8395d7 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -2001,7 +2001,7 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis(
     tcx: TyCtxt<'_>,
     closure_id: hir::HirId,
 ) -> bool {
-    if tcx.sess.rust_2021() {
+    if tcx.sess.at_least_rust_2021() {
         return false;
     }
 
@@ -2247,5 +2247,5 @@ fn truncate_capture_for_optimization(
 fn enable_precise_capture(span: Span) -> bool {
     // We use span here to ensure that if the closure was generated by a macro with a different
     // edition.
-    span.rust_2021()
+    span.at_least_rust_2021()
 }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3f420f19efe..5b417e008cf 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -251,6 +251,7 @@ pub struct Config {
     pub input: Input,
     pub output_dir: Option<PathBuf>,
     pub output_file: Option<OutFileName>,
+    pub ice_file: Option<PathBuf>,
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     pub locale_resources: &'static [&'static str],
 
@@ -315,6 +316,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
                 config.lint_caps,
                 config.make_codegen_backend,
                 registry.clone(),
+                config.ice_file,
             );
 
             if let Some(parse_sess_created) = config.parse_sess_created {
@@ -346,7 +348,11 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     )
 }
 
-pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
+pub fn try_print_query_stack(
+    handler: &Handler,
+    num_frames: Option<usize>,
+    file: Option<std::fs::File>,
+) {
     eprintln!("query stack during panic:");
 
     // Be careful relying on global state here: this code is called from
@@ -358,7 +364,8 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
                 QueryCtxt::new(icx.tcx),
                 icx.query,
                 handler,
-                num_frames
+                num_frames,
+                file,
             ))
         } else {
             0
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 09141afd137..5c6c3491b38 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -67,6 +67,7 @@ fn mk_session(handler: &mut EarlyErrorHandler, matches: getopts::Matches) -> (Se
         None,
         None,
         "",
+        None,
     );
     (sess, cfg)
 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 035ea2414f7..12d33f06309 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -70,6 +70,7 @@ pub fn create_session(
         Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
     >,
     descriptions: Registry,
+    ice_file: Option<PathBuf>,
 ) -> (Session, Box<dyn CodegenBackend>) {
     let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend {
         make_codegen_backend(&sopts)
@@ -111,6 +112,7 @@ pub fn create_session(
         file_loader,
         target_override,
         rustc_version_str().unwrap_or("unknown"),
+        ice_file,
     );
 
     codegen_backend.init(&sess);
diff --git a/compiler/rustc_metadata/src/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs
index d1c2f3104d0..154eb684f11 100644
--- a/compiler/rustc_metadata/src/foreign_modules.rs
+++ b/compiler/rustc_metadata/src/foreign_modules.rs
@@ -1,19 +1,28 @@
+use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::cstore::ForeignModule;
 
-pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
-    let mut modules = Vec::new();
+pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> FxIndexMap<DefId, ForeignModule> {
+    let mut modules = FxIndexMap::default();
+
+    // We need to collect all the `ForeignMod`, even if they are empty.
     for id in tcx.hir().items() {
         if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
             continue;
         }
+
+        let def_id = id.owner_id.to_def_id();
         let item = tcx.hir().item(id);
-        if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
+
+        if let hir::ItemKind::ForeignMod { abi, items } = item.kind {
             let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
-            modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
+            modules.insert(def_id, ForeignModule { def_id, abi, foreign_items });
         }
     }
+
     modules
 }
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index a1511c4b570..44195996762 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -511,7 +511,7 @@ impl<'a> CrateLocator<'a> {
             rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?,
             dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?,
         };
-        Ok(slot.map(|(svh, metadata)| (svh, Library { source, metadata })))
+        Ok(slot.map(|(svh, metadata, _)| (svh, Library { source, metadata })))
     }
 
     fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
@@ -535,11 +535,13 @@ impl<'a> CrateLocator<'a> {
     // read the metadata from it if `*slot` is `None`. If the metadata couldn't
     // be read, it is assumed that the file isn't a valid rust library (no
     // errors are emitted).
+    //
+    // The `PathBuf` in `slot` will only be used for diagnostic purposes.
     fn extract_one(
         &mut self,
         m: FxHashMap<PathBuf, PathKind>,
         flavor: CrateFlavor,
-        slot: &mut Option<(Svh, MetadataBlob)>,
+        slot: &mut Option<(Svh, MetadataBlob, PathBuf)>,
     ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {
         // If we are producing an rlib, and we've already loaded metadata, then
         // we should not attempt to discover further crate sources (unless we're
@@ -550,16 +552,9 @@ impl<'a> CrateLocator<'a> {
         //
         // See also #68149 which provides more detail on why emitting the
         // dependency on the rlib is a bad thing.
-        //
-        // We currently do not verify that these other sources are even in sync,
-        // and this is arguably a bug (see #10786), but because reading metadata
-        // is quite slow (especially from dylibs) we currently do not read it
-        // from the other crate sources.
         if slot.is_some() {
             if m.is_empty() || !self.needs_crate_flavor(flavor) {
                 return Ok(None);
-            } else if m.len() == 1 {
-                return Ok(Some(m.into_iter().next().unwrap()));
             }
         }
 
@@ -610,8 +605,7 @@ impl<'a> CrateLocator<'a> {
                         candidates,
                     ));
                 }
-                err_data = Some(vec![ret.as_ref().unwrap().0.clone()]);
-                *slot = None;
+                err_data = Some(vec![slot.take().unwrap().2]);
             }
             if let Some(candidates) = &mut err_data {
                 candidates.push(lib);
@@ -644,7 +638,7 @@ impl<'a> CrateLocator<'a> {
                     continue;
                 }
             }
-            *slot = Some((hash, metadata));
+            *slot = Some((hash, metadata, lib.clone()));
             ret = Some((lib, kind));
         }
 
@@ -814,19 +808,26 @@ fn get_metadata_section<'p>(
             let compressed_len = u32::from_be_bytes(len_bytes) as usize;
 
             // Header is okay -> inflate the actual metadata
-            let compressed_bytes = &buf[data_start..(data_start + compressed_len)];
-            debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
-            // Assume the decompressed data will be at least the size of the compressed data, so we
-            // don't have to grow the buffer as much.
-            let mut inflated = Vec::with_capacity(compressed_bytes.len());
-            FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated).map_err(|_| {
-                MetadataError::LoadFailure(format!(
-                    "failed to decompress metadata: {}",
-                    filename.display()
-                ))
-            })?;
+            let compressed_bytes = buf.slice(|buf| &buf[data_start..(data_start + compressed_len)]);
+            if &compressed_bytes[..cmp::min(METADATA_HEADER.len(), compressed_bytes.len())]
+                == METADATA_HEADER
+            {
+                // The metadata was not actually compressed.
+                compressed_bytes
+            } else {
+                debug!("inflating {} bytes of compressed metadata", compressed_bytes.len());
+                // Assume the decompressed data will be at least the size of the compressed data, so we
+                // don't have to grow the buffer as much.
+                let mut inflated = Vec::with_capacity(compressed_bytes.len());
+                FrameDecoder::new(&*compressed_bytes).read_to_end(&mut inflated).map_err(|_| {
+                    MetadataError::LoadFailure(format!(
+                        "failed to decompress metadata: {}",
+                        filename.display()
+                    ))
+                })?;
 
-            slice_owned(inflated, Deref::deref)
+                slice_owned(inflated, Deref::deref)
+            }
         }
         CrateFlavor::Rmeta => {
             // mmap the file, because only a small fraction of it is read.
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 9e0bf81d58d..ca5043cc263 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -1,15 +1,17 @@
 use rustc_ast::{NestedMetaItem, CRATE_NODE_ID};
 use rustc_attr as attr;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir as hir;
-use rustc_hir::def::DefKind;
+use rustc_middle::query::LocalCrate;
 use rustc_middle::ty::{List, ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_session::config::CrateType;
-use rustc_session::cstore::{DllCallingConvention, DllImport, NativeLib, PeImportNameType};
+use rustc_session::cstore::{
+    DllCallingConvention, DllImport, ForeignModule, NativeLib, PeImportNameType,
+};
 use rustc_session::parse::feature_err;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
+use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -66,10 +68,12 @@ fn find_bundled_library(
     None
 }
 
-pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
+pub(crate) fn collect(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> Vec<NativeLib> {
     let mut collector = Collector { tcx, libs: Vec::new() };
-    for id in tcx.hir().items() {
-        collector.process_item(id);
+    if tcx.sess.opts.unstable_opts.link_directives {
+        for module in tcx.foreign_modules(LOCAL_CRATE).values() {
+            collector.process_module(module);
+        }
     }
     collector.process_command_line();
     collector.libs
@@ -88,29 +92,20 @@ struct Collector<'tcx> {
 }
 
 impl<'tcx> Collector<'tcx> {
-    fn process_item(&mut self, id: rustc_hir::ItemId) {
-        if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
-            return;
-        }
+    fn process_module(&mut self, module: &ForeignModule) {
+        let ForeignModule { def_id, abi, ref foreign_items } = *module;
+        let def_id = def_id.expect_local();
 
-        let it = self.tcx.hir().item(id);
-        let hir::ItemKind::ForeignMod { abi, items: foreign_mod_items } = it.kind else {
-            return;
-        };
+        let sess = self.tcx.sess;
 
         if matches!(abi, Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic) {
             return;
         }
 
         // Process all of the #[link(..)]-style arguments
-        let sess = self.tcx.sess;
         let features = self.tcx.features();
 
-        if !sess.opts.unstable_opts.link_directives {
-            return;
-        }
-
-        for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
+        for m in self.tcx.get_attrs(def_id, sym::link) {
             let Some(items) = m.meta_item_list() else {
                 continue;
             };
@@ -340,9 +335,9 @@ impl<'tcx> Collector<'tcx> {
                     if name.as_str().contains('\0') {
                         sess.emit_err(errors::RawDylibNoNul { span: name_span });
                     }
-                    foreign_mod_items
+                    foreign_items
                         .iter()
-                        .map(|child_item| {
+                        .map(|&child_item| {
                             self.build_dll_import(
                                 abi,
                                 import_name_type.map(|(import_name_type, _)| import_name_type),
@@ -352,21 +347,12 @@ impl<'tcx> Collector<'tcx> {
                         .collect()
                 }
                 _ => {
-                    for child_item in foreign_mod_items {
-                        if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
-                            && self
-                                .tcx
-                                .codegen_fn_attrs(child_item.id.owner_id)
-                                .link_ordinal
-                                .is_some()
+                    for &child_item in foreign_items {
+                        if self.tcx.def_kind(child_item).has_codegen_attrs()
+                            && self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
                         {
-                            let link_ordinal_attr = self
-                                .tcx
-                                .hir()
-                                .attrs(child_item.id.owner_id.into())
-                                .iter()
-                                .find(|a| a.has_name(sym::link_ordinal))
-                                .unwrap();
+                            let link_ordinal_attr =
+                                self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
                             sess.emit_err(errors::LinkOrdinalRawDylib {
                                 span: link_ordinal_attr.span,
                             });
@@ -384,7 +370,7 @@ impl<'tcx> Collector<'tcx> {
                 filename,
                 kind,
                 cfg,
-                foreign_module: Some(it.owner_id.to_def_id()),
+                foreign_module: Some(def_id.to_def_id()),
                 verbatim,
                 dll_imports,
             });
@@ -476,10 +462,10 @@ impl<'tcx> Collector<'tcx> {
         }
     }
 
-    fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
+    fn i686_arg_list_size(&self, item: DefId) -> usize {
         let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
             self.tcx
-                .type_of(item.id.owner_id)
+                .type_of(item)
                 .instantiate_identity()
                 .fn_sig(self.tcx)
                 .inputs()
@@ -505,8 +491,10 @@ impl<'tcx> Collector<'tcx> {
         &self,
         abi: Abi,
         import_name_type: Option<PeImportNameType>,
-        item: &hir::ForeignItemRef,
+        item: DefId,
     ) -> DllImport {
+        let span = self.tcx.def_span(item);
+
         let calling_convention = if self.tcx.sess.target.arch == "x86" {
             match abi {
                 Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
@@ -520,29 +508,29 @@ impl<'tcx> Collector<'tcx> {
                     DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
                 }
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span: item.span });
+                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span });
                 }
             }
         };
 
-        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
+        let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item);
         let import_name_type = codegen_fn_attrs
             .link_ordinal
             .map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
 
         DllImport {
-            name: codegen_fn_attrs.link_name.unwrap_or(item.ident.name),
+            name: codegen_fn_attrs.link_name.unwrap_or(self.tcx.item_name(item)),
             import_name_type,
             calling_convention,
-            span: item.span,
-            is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
+            span,
+            is_fn: self.tcx.def_kind(item).is_fn_like(),
         }
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 8fa1d365728..9e67bb655d4 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -34,7 +34,7 @@ use rustc_session::cstore::{
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnIndex;
 use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::{self, BytePos, ExpnId, Pos, Span, SyntaxContext, DUMMY_SP};
+use rustc_span::{self, BytePos, ExpnId, Pos, Span, SpanData, SyntaxContext, DUMMY_SP};
 
 use proc_macro::bridge::client::ProcMacro;
 use std::iter::TrustedLen;
@@ -513,11 +513,26 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
     fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
+        let mode = SpanEncodingMode::decode(decoder);
+        let data = match mode {
+            SpanEncodingMode::Direct => SpanData::decode(decoder),
+            SpanEncodingMode::Shorthand(position) => decoder.with_position(position, |decoder| {
+                let mode = SpanEncodingMode::decode(decoder);
+                debug_assert!(matches!(mode, SpanEncodingMode::Direct));
+                SpanData::decode(decoder)
+            }),
+        };
+        Span::new(data.lo, data.hi, data.ctxt, data.parent)
+    }
+}
+
+impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SpanData {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SpanData {
         let ctxt = SyntaxContext::decode(decoder);
         let tag = u8::decode(decoder);
 
         if tag == TAG_PARTIAL_SPAN {
-            return DUMMY_SP.with_ctxt(ctxt);
+            return DUMMY_SP.with_ctxt(ctxt).data();
         }
 
         debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
@@ -612,7 +627,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
         let hi = hi + source_file.translated_source_file.start_pos;
 
         // Do not try to decode parent for foreign spans.
-        Span::new(lo, hi, ctxt, None)
+        SpanData { lo, hi, ctxt, parent: None }
     }
 }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 848535fb395..a8815ee0908 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -403,10 +403,8 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                         .contains(&id)
                 })
         },
-        native_libraries: |tcx, LocalCrate| native_libs::collect(tcx),
-        foreign_modules: |tcx, LocalCrate| {
-            foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
-        },
+        native_libraries: native_libs::collect,
+        foreign_modules: foreign_modules::collect,
 
         // Returns a map from a sufficiently visible external item (i.e., an
         // external item that is visible from at least one local module) to a
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 2785732727f..ac86110f2bd 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -37,7 +37,7 @@ use rustc_session::config::{CrateType, OptLevel};
 use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
+use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SpanData, SyntaxContext};
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
@@ -53,6 +53,7 @@ pub(super) struct EncodeContext<'a, 'tcx> {
     tables: TableBuilders,
 
     lazy_state: LazyState,
+    span_shorthands: FxHashMap<Span, usize>,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
     predicate_shorthands: FxHashMap<ty::PredicateKind<'tcx>, usize>,
 
@@ -177,8 +178,20 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for ExpnId {
 
 impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
     fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
-        let span = self.data();
+        match s.span_shorthands.entry(*self) {
+            Entry::Occupied(o) => SpanEncodingMode::Shorthand(*o.get()).encode(s),
+            Entry::Vacant(v) => {
+                let position = s.opaque.position();
+                v.insert(position);
+                SpanEncodingMode::Direct.encode(s);
+                self.data().encode(s);
+            }
+        }
+    }
+}
 
+impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for SpanData {
+    fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) {
         // Don't serialize any `SyntaxContext`s from a proc-macro crate,
         // since we don't load proc-macro dependencies during serialization.
         // This means that any hygiene information from macros used *within*
@@ -213,7 +226,7 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
         if s.is_proc_macro {
             SyntaxContext::root().encode(s);
         } else {
-            span.ctxt.encode(s);
+            self.ctxt.encode(s);
         }
 
         if self.is_dummy() {
@@ -221,18 +234,18 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
         }
 
         // The Span infrastructure should make sure that this invariant holds:
-        debug_assert!(span.lo <= span.hi);
+        debug_assert!(self.lo <= self.hi);
 
-        if !s.source_file_cache.0.contains(span.lo) {
+        if !s.source_file_cache.0.contains(self.lo) {
             let source_map = s.tcx.sess.source_map();
-            let source_file_index = source_map.lookup_source_file_idx(span.lo);
+            let source_file_index = source_map.lookup_source_file_idx(self.lo);
             s.source_file_cache =
                 (source_map.files()[source_file_index].clone(), source_file_index);
         }
         let (ref source_file, source_file_index) = s.source_file_cache;
-        debug_assert!(source_file.contains(span.lo));
+        debug_assert!(source_file.contains(self.lo));
 
-        if !source_file.contains(span.hi) {
+        if !source_file.contains(self.hi) {
             // Unfortunately, macro expansion still sometimes generates Spans
             // that malformed in this way.
             return TAG_PARTIAL_SPAN.encode(s);
@@ -286,11 +299,11 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Span {
 
         // Encode the start position relative to the file start, so we profit more from the
         // variable-length integer encoding.
-        let lo = span.lo - source_file.start_pos;
+        let lo = self.lo - source_file.start_pos;
 
         // Encode length which is usually less than span.hi and profits more
         // from the variable-length integer encoding that we use.
-        let len = span.hi - span.lo;
+        let len = self.hi - self.lo;
 
         tag.encode(s);
         lo.encode(s);
@@ -2182,6 +2195,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
         feat: tcx.features(),
         tables: Default::default(),
         lazy_state: LazyState::NoNode,
+        span_shorthands: Default::default(),
         type_shorthands: Default::default(),
         predicate_shorthands: Default::default(),
         source_file_cache,
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index f6087fbe8f6..0bc16fc64ff 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -66,6 +66,12 @@ const METADATA_VERSION: u8 = 8;
 /// unsigned integer, and further followed by the rustc version string.
 pub const METADATA_HEADER: &[u8] = &[b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
+#[derive(Encodable, Decodable)]
+enum SpanEncodingMode {
+    Shorthand(usize),
+    Direct,
+}
+
 /// A value of type T referred to by its absolute position
 /// in the metadata, and which can be decoded lazily.
 ///
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index c4601a1fb41..02fd6ed7ba6 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -100,6 +100,8 @@ bitflags! {
         const REALLOCATOR               = 1 << 18;
         /// `#[rustc_allocator_zeroed]`: a hint to LLVM that the function only allocates zeroed memory.
         const ALLOCATOR_ZEROED          = 1 << 19;
+        /// `#[no_builtins]`: indicates that disable implicit builtin knowledge of functions for the function.
+        const NO_BUILTINS               = 1 << 20;
     }
 }
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c304245ca39..062adc9ec54 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1579,7 +1579,7 @@ rustc_queries! {
     }
 
     /// Returns a list of all `extern` blocks of a crate.
-    query foreign_modules(_: CrateNum) -> &'tcx FxHashMap<DefId, ForeignModule> {
+    query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap<DefId, ForeignModule> {
         arena_cache
         desc { "looking up the foreign modules of a linked crate" }
         separate_provide_extern
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 70eb389b406..e5633223464 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1932,7 +1932,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
     fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
         self.empty_path = true;
         if cnum == LOCAL_CRATE {
-            if self.tcx.sess.rust_2018() {
+            if self.tcx.sess.at_least_rust_2018() {
                 // We add the `crate::` keyword on Rust 2018, only when desired.
                 if SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) {
                     write!(self, "{}", kw::Crate)?;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index c122230b841..7756d5d4879 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -730,5 +730,5 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
 /// Precise capture is enabled if user is using Rust Edition 2021 or higher.
 fn enable_precise_capture(closure_span: Span) -> bool {
-    closure_span.rust_2021()
+    closure_span.at_least_rust_2021()
 }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 7ede4fbc3d9..3ecdbc36248 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1309,7 +1309,7 @@ impl<'a> Parser<'a> {
 
     /// Assuming we have just parsed `.`, continue parsing into an expression.
     fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
-        if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) {
+        if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await) {
             return Ok(self.mk_await_expr(self_arg, lo));
         }
 
@@ -1442,8 +1442,8 @@ impl<'a> Parser<'a> {
             self.parse_expr_let()
         } else if self.eat_keyword(kw::Underscore) {
             Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore))
-        } else if self.token.uninterpolated_span().rust_2018() {
-            // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly.
+        } else if self.token.uninterpolated_span().at_least_rust_2018() {
+            // `Span:.at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
             if self.check_keyword(kw::Async) {
                 if self.is_async_block() {
                     // Check for `async {` and `async move {`.
@@ -2230,7 +2230,7 @@ impl<'a> Parser<'a> {
         let movability =
             if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable };
 
-        let asyncness = if self.token.uninterpolated_span().rust_2018() {
+        let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() {
             self.parse_asyncness(Case::Sensitive)
         } else {
             Async::No
@@ -3014,7 +3014,7 @@ impl<'a> Parser<'a> {
     fn is_try_block(&self) -> bool {
         self.token.is_keyword(kw::Try)
             && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
-            && self.token.uninterpolated_span().rust_2018()
+            && self.token.uninterpolated_span().at_least_rust_2018()
     }
 
     /// Parses an `async move? {...}` expression.
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index e4d843b7c8b..2e1a61e634e 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1210,7 +1210,8 @@ impl<'a> Parser<'a> {
     fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
         // Avoid const blocks and const closures to be parsed as const items
         if (self.check_const_closure() == is_closure)
-            && self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace))
+            && !self
+                .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
             && self.eat_keyword_case(kw::Const, case)
         {
             Const::Yes(self.prev_token.uninterpolated_span())
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index a29b696aea8..3bb50b05aa3 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -608,7 +608,7 @@ impl<'a> Parser<'a> {
     /// Is a `dyn B0 + ... + Bn` type allowed here?
     fn is_explicit_dyn_type(&mut self) -> bool {
         self.check_keyword(kw::Dyn)
-            && (self.token.uninterpolated_span().rust_2018()
+            && (self.token.uninterpolated_span().at_least_rust_2018()
                 || self.look_ahead(1, |t| {
                     (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star))
                         && !can_continue_type_after_non_fn_ident(t)
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 7de84db211e..88452ccdf05 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -109,6 +109,8 @@ pub struct Argument<'a> {
 pub struct FormatSpec<'a> {
     /// Optionally specified character to fill alignment with.
     pub fill: Option<char>,
+    /// Span of the optionally specified fill character.
+    pub fill_span: Option<InnerSpan>,
     /// Optionally specified alignment.
     pub align: Alignment,
     /// The `+` or `-` flag.
@@ -264,7 +266,7 @@ impl<'a> Iterator for Parser<'a> {
                         Some(String(self.string(pos + 1)))
                     } else {
                         let arg = self.argument(lbrace_end);
-                        if let Some(rbrace_pos) = self.must_consume('}') {
+                        if let Some(rbrace_pos) = self.consume_closing_brace(&arg) {
                             if self.is_source_literal {
                                 let lbrace_byte_pos = self.to_span_index(pos);
                                 let rbrace_byte_pos = self.to_span_index(rbrace_pos);
@@ -450,69 +452,51 @@ impl<'a> Parser<'a> {
 
     /// Forces consumption of the specified character. If the character is not
     /// found, an error is emitted.
-    fn must_consume(&mut self, c: char) -> Option<usize> {
+    fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<usize> {
         self.ws();
 
-        if let Some(&(pos, maybe)) = self.cur.peek() {
-            if c == maybe {
+        let pos;
+        let description;
+
+        if let Some(&(peek_pos, maybe)) = self.cur.peek() {
+            if maybe == '}' {
                 self.cur.next();
-                Some(pos)
-            } else {
-                let pos = self.to_span_index(pos);
-                let description = format!("expected `'}}'`, found `{maybe:?}`");
-                let label = "expected `}`".to_owned();
-                let (note, secondary_label) = if c == '}' {
-                    (
-                        Some(
-                            "if you intended to print `{`, you can escape it using `{{`".to_owned(),
-                        ),
-                        self.last_opening_brace
-                            .map(|sp| ("because of this opening brace".to_owned(), sp)),
-                    )
-                } else {
-                    (None, None)
-                };
-                self.errors.push(ParseError {
-                    description,
-                    note,
-                    label,
-                    span: pos.to(pos),
-                    secondary_label,
-                    should_be_replaced_with_positional_argument: false,
-                });
-                None
+                return Some(peek_pos);
             }
+
+            pos = peek_pos;
+            description = format!("expected `'}}'`, found `{maybe:?}`");
         } else {
-            let description = format!("expected `{c:?}` but string was terminated");
+            description = "expected `'}'` but string was terminated".to_owned();
             // point at closing `"`
-            let pos = self.input.len() - if self.append_newline { 1 } else { 0 };
-            let pos = self.to_span_index(pos);
-            if c == '}' {
-                let label = format!("expected `{c:?}`");
-                let (note, secondary_label) = if c == '}' {
-                    (
-                        Some(
-                            "if you intended to print `{`, you can escape it using `{{`".to_owned(),
-                        ),
-                        self.last_opening_brace
-                            .map(|sp| ("because of this opening brace".to_owned(), sp)),
-                    )
-                } else {
-                    (None, None)
-                };
-                self.errors.push(ParseError {
-                    description,
-                    note,
-                    label,
-                    span: pos.to(pos),
-                    secondary_label,
-                    should_be_replaced_with_positional_argument: false,
-                });
-            } else {
-                self.err(description, format!("expected `{c:?}`"), pos.to(pos));
-            }
-            None
+            pos = self.input.len() - if self.append_newline { 1 } else { 0 };
         }
+
+        let pos = self.to_span_index(pos);
+
+        let label = "expected `'}'`".to_owned();
+        let (note, secondary_label) = if arg.format.fill == Some('}') {
+            (
+                Some("the character `'}'` is interpreted as a fill character because of the `:` that precedes it".to_owned()),
+                arg.format.fill_span.map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)),
+            )
+        } else {
+            (
+                Some("if you intended to print `{`, you can escape it using `{{`".to_owned()),
+                self.last_opening_brace.map(|sp| ("because of this opening brace".to_owned(), sp)),
+            )
+        };
+
+        self.errors.push(ParseError {
+            description,
+            note,
+            label,
+            span: pos.to(pos),
+            secondary_label,
+            should_be_replaced_with_positional_argument: false,
+        });
+
+        None
     }
 
     /// Consumes all whitespace characters until the first non-whitespace character
@@ -608,6 +592,7 @@ impl<'a> Parser<'a> {
     fn format(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
+            fill_span: None,
             align: AlignUnknown,
             sign: None,
             alternate: false,
@@ -625,9 +610,10 @@ impl<'a> Parser<'a> {
         }
 
         // fill character
-        if let Some(&(_, c)) = self.cur.peek() {
+        if let Some(&(idx, c)) = self.cur.peek() {
             if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) {
                 spec.fill = Some(c);
+                spec.fill_span = Some(self.span(idx, idx + 1));
                 self.cur.next();
             }
         }
@@ -722,6 +708,7 @@ impl<'a> Parser<'a> {
     fn inline_asm(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
+            fill_span: None,
             align: AlignUnknown,
             sign: None,
             alternate: false,
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 45314e2fb55..0c594f9104c 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -9,6 +9,7 @@ fn same(fmt: &'static str, p: &[Piece<'static>]) {
 fn fmtdflt() -> FormatSpec<'static> {
     return FormatSpec {
         fill: None,
+        fill_span: None,
         align: AlignUnknown,
         sign: None,
         alternate: false,
@@ -128,6 +129,7 @@ fn format_type() {
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -152,6 +154,7 @@ fn format_align_fill() {
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignRight,
                 sign: None,
                 alternate: false,
@@ -173,6 +176,7 @@ fn format_align_fill() {
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('0'),
+                fill_span: Some(InnerSpan::new(4, 5)),
                 align: AlignLeft,
                 sign: None,
                 alternate: false,
@@ -194,6 +198,7 @@ fn format_align_fill() {
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: Some('*'),
+                fill_span: Some(InnerSpan::new(4, 5)),
                 align: AlignLeft,
                 sign: None,
                 alternate: false,
@@ -218,6 +223,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -239,6 +245,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -260,6 +267,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 3 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -281,6 +289,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -302,6 +311,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -323,6 +333,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -344,6 +355,7 @@ fn format_counts() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: None,
                 alternate: false,
@@ -368,6 +380,7 @@ fn format_flags() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: Some(Sign::Minus),
                 alternate: false,
@@ -389,6 +402,7 @@ fn format_flags() {
             position_span: InnerSpan { start: 2, end: 2 },
             format: FormatSpec {
                 fill: None,
+                fill_span: None,
                 align: AlignUnknown,
                 sign: Some(Sign::Plus),
                 alternate: true,
@@ -415,6 +429,7 @@ fn format_mixture() {
                 position_span: InnerSpan { start: 7, end: 8 },
                 format: FormatSpec {
                     fill: None,
+                    fill_span: None,
                     align: AlignUnknown,
                     sign: None,
                     alternate: false,
diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl
index 49b423d1ade..d5fed8fe179 100644
--- a/compiler/rustc_query_system/messages.ftl
+++ b/compiler/rustc_query_system/messages.ftl
@@ -1,4 +1,5 @@
 query_system_cycle = cycle detected when {$stack_bottom}
+    .note = see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
 
diff --git a/compiler/rustc_query_system/src/error.rs b/compiler/rustc_query_system/src/error.rs
index cf2f04c7486..e49e78cc7c4 100644
--- a/compiler/rustc_query_system/src/error.rs
+++ b/compiler/rustc_query_system/src/error.rs
@@ -57,6 +57,8 @@ pub struct Cycle {
     pub alias: Option<Alias>,
     #[subdiagnostic]
     pub cycle_usage: Option<CycleUsage>,
+    #[note]
+    pub note_span: (),
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index f45f7ca5da6..d2140161f1d 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -13,6 +13,7 @@ use rustc_session::Session;
 use rustc_span::Span;
 
 use std::hash::Hash;
+use std::io::Write;
 use std::num::NonZeroU64;
 
 #[cfg(parallel_compiler)]
@@ -607,6 +608,7 @@ pub(crate) fn report_cycle<'a, D: DepKind>(
         alias,
         cycle_usage: cycle_usage,
         stack_count,
+        note_span: (),
     };
 
     cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic)
@@ -617,30 +619,50 @@ pub fn print_query_stack<Qcx: QueryContext>(
     mut current_query: Option<QueryJobId>,
     handler: &Handler,
     num_frames: Option<usize>,
+    mut file: Option<std::fs::File>,
 ) -> usize {
     // Be careful relying on global state here: this code is called from
     // a panic hook, which means that the global `Handler` may be in a weird
     // state if it was responsible for triggering the panic.
-    let mut i = 0;
+    let mut count_printed = 0;
+    let mut count_total = 0;
     let query_map = qcx.try_collect_active_jobs();
 
+    if let Some(ref mut file) = file {
+        let _ = writeln!(file, "\n\nquery stack during panic:");
+    }
     while let Some(query) = current_query {
-        if Some(i) == num_frames {
-            break;
-        }
         let Some(query_info) = query_map.as_ref().and_then(|map| map.get(&query)) else {
             break;
         };
-        let mut diag = Diagnostic::new(
-            Level::FailureNote,
-            format!("#{} [{:?}] {}", i, query_info.query.dep_kind, query_info.query.description),
-        );
-        diag.span = query_info.job.span.into();
-        handler.force_print_diagnostic(diag);
+        if Some(count_printed) < num_frames || num_frames.is_none() {
+            // Only print to stderr as many stack frames as `num_frames` when present.
+            let mut diag = Diagnostic::new(
+                Level::FailureNote,
+                format!(
+                    "#{} [{:?}] {}",
+                    count_printed, query_info.query.dep_kind, query_info.query.description
+                ),
+            );
+            diag.span = query_info.job.span.into();
+            handler.force_print_diagnostic(diag);
+            count_printed += 1;
+        }
+
+        if let Some(ref mut file) = file {
+            let _ = writeln!(
+                file,
+                "#{} [{:?}] {}",
+                count_total, query_info.query.dep_kind, query_info.query.description
+            );
+        }
 
         current_query = query_info.job.parent;
-        i += 1;
+        count_total += 1;
     }
 
-    i
+    if let Some(ref mut file) = file {
+        let _ = writeln!(file, "end of query stack");
+    }
+    count_printed
 }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index dc35c8b176f..3228e8d52f0 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -440,7 +440,7 @@ impl Resolver<'_, '_> {
 
             // If we are not in Rust 2018 edition, then we don't make any further
             // suggestions.
-            if !tcx.sess.rust_2018() {
+            if !tcx.sess.at_least_rust_2018() {
                 continue;
             }
 
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index d3dcdfa4275..2cfde2f62d8 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1203,7 +1203,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     if filter_fn(res) {
                         // create the path
                         let mut segms = path_segments.clone();
-                        if lookup_ident.span.rust_2018() {
+                        if lookup_ident.span.at_least_rust_2018() {
                             // crate-local absolute paths start with `crate::` in edition 2018
                             // FIXME: may also be stabilized for Rust 2015 (Issues #45477, #44660)
                             segms.insert(0, ast::PathSegment::from_ident(crate_name));
@@ -1268,7 +1268,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     path_segments.push(ast::PathSegment::from_ident(ident));
 
                     let is_extern_crate_that_also_appears_in_prelude =
-                        name_binding.is_extern_crate() && lookup_ident.span.rust_2018();
+                        name_binding.is_extern_crate() && lookup_ident.span.at_least_rust_2018();
 
                     if !is_extern_crate_that_also_appears_in_prelude {
                         // add the module to the lookup
@@ -1315,7 +1315,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             &filter_fn,
         );
 
-        if lookup_ident.span.rust_2018() {
+        if lookup_ident.span.at_least_rust_2018() {
             let extern_prelude_names = self.extern_prelude.clone();
             for (ident, _) in extern_prelude_names.into_iter() {
                 if ident.span.from_expansion() {
@@ -1568,7 +1568,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     "consider adding an explicit import of `{ident}` to disambiguate"
                 ))
             }
-            if b.is_extern_crate() && ident.span.rust_2018() {
+            if b.is_extern_crate() && ident.span.at_least_rust_2018() {
                 help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
             }
             match misc {
@@ -1973,7 +1973,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 if fst.ident.name == kw::PathRoot && !snd.ident.is_path_segment_keyword() => {}
             // `ident::...` on 2018.
             (Some(fst), _)
-                if fst.ident.span.rust_2018() && !fst.ident.is_path_segment_keyword() =>
+                if fst.ident.span.at_least_rust_2018() && !fst.ident.is_path_segment_keyword() =>
             {
                 // Insert a placeholder that's later replaced by `self`/`super`/etc.
                 path.insert(0, Segment::from_ident(Ident::empty()));
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 520fab1f0c8..de431444769 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1417,13 +1417,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         ));
                         continue;
                     }
-                    if name == kw::PathRoot && ident.span.rust_2018() {
+                    if name == kw::PathRoot && ident.span.at_least_rust_2018() {
                         module = Some(ModuleOrUniformRoot::ExternPrelude);
                         continue;
                     }
                     if name == kw::PathRoot
                         && ident.span.is_rust_2015()
-                        && self.tcx.sess.rust_2018()
+                        && self.tcx.sess.at_least_rust_2018()
                     {
                         // `::a::b` from 2015 macro on 2018 global edition
                         module = Some(ModuleOrUniformRoot::CrateRootAndExternPrelude);
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index dc475e8c6d5..c53a355b533 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -13,6 +13,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 use rustc_target::spec::Target;
 
 use std::any::Any;
@@ -147,6 +148,7 @@ pub enum DllCallingConvention {
 pub struct ForeignModule {
     pub foreign_items: Vec<DefId>,
     pub def_id: DefId,
+    pub abi: Abi,
 }
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index d5326df9ad9..b0a67c564ce 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -231,6 +231,7 @@ impl ParseSess {
             Some(sm.clone()),
             None,
             fallback_bundle,
+            None,
         );
         ParseSess::with_span_handler(handler, sm)
     }
@@ -261,12 +262,20 @@ impl ParseSess {
     pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
         let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let fatal_handler =
-            Handler::with_tty_emitter(ColorConfig::Auto, false, None, None, None, fallback_bundle);
+        let fatal_handler = Handler::with_tty_emitter(
+            ColorConfig::Auto,
+            false,
+            None,
+            None,
+            None,
+            fallback_bundle,
+            None,
+        );
         let handler = Handler::with_emitter(
             false,
             None,
             Box::new(SilentEmitter { fatal_handler, fatal_note }),
+            None,
         );
         ParseSess::with_span_handler(handler, sm)
     }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 5be122ffbde..0f5d3b291db 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -995,18 +995,18 @@ impl Session {
     }
 
     /// Are we allowed to use features from the Rust 2018 edition?
-    pub fn rust_2018(&self) -> bool {
-        self.edition().rust_2018()
+    pub fn at_least_rust_2018(&self) -> bool {
+        self.edition().at_least_rust_2018()
     }
 
     /// Are we allowed to use features from the Rust 2021 edition?
-    pub fn rust_2021(&self) -> bool {
-        self.edition().rust_2021()
+    pub fn at_least_rust_2021(&self) -> bool {
+        self.edition().at_least_rust_2021()
     }
 
     /// Are we allowed to use features from the Rust 2024 edition?
-    pub fn rust_2024(&self) -> bool {
-        self.edition().rust_2024()
+    pub fn at_least_rust_2024(&self) -> bool {
+        self.edition().at_least_rust_2024()
     }
 
     /// Returns `true` if we should use the PLT for shared library calls.
@@ -1392,6 +1392,7 @@ pub fn build_session(
     file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
     target_override: Option<Target>,
     cfg_version: &'static str,
+    ice_file: Option<PathBuf>,
 ) -> Session {
     // FIXME: This is not general enough to make the warning lint completely override
     // normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -1440,6 +1441,7 @@ pub fn build_session(
     let span_diagnostic = rustc_errors::Handler::with_emitter_and_flags(
         emitter,
         sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings),
+        ice_file,
     );
 
     let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
@@ -1731,7 +1733,7 @@ pub struct EarlyErrorHandler {
 impl EarlyErrorHandler {
     pub fn new(output: ErrorOutputType) -> Self {
         let emitter = mk_emitter(output);
-        Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter) }
+        Self { handler: rustc_errors::Handler::with_emitter(true, None, emitter, None) }
     }
 
     pub fn abort_if_errors(&self) {
@@ -1745,7 +1747,7 @@ impl EarlyErrorHandler {
         self.handler.abort_if_errors();
 
         let emitter = mk_emitter(output);
-        self.handler = Handler::with_emitter(true, None, emitter);
+        self.handler = Handler::with_emitter(true, None, emitter, None);
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs
index f16db69aae2..608b8c24bde 100644
--- a/compiler/rustc_span/src/edition.rs
+++ b/compiler/rustc_span/src/edition.rs
@@ -82,17 +82,17 @@ impl Edition {
     }
 
     /// Are we allowed to use features from the Rust 2018 edition?
-    pub fn rust_2018(self) -> bool {
+    pub fn at_least_rust_2018(self) -> bool {
         self >= Edition::Edition2018
     }
 
     /// Are we allowed to use features from the Rust 2021 edition?
-    pub fn rust_2021(self) -> bool {
+    pub fn at_least_rust_2021(self) -> bool {
         self >= Edition::Edition2021
     }
 
     /// Are we allowed to use features from the Rust 2024 edition?
-    pub fn rust_2024(self) -> bool {
+    pub fn at_least_rust_2024(self) -> bool {
         self >= Edition::Edition2024
     }
 }
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 5c56337d1e0..ecaa82874a3 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -707,24 +707,28 @@ impl Span {
         self.ctxt().edition()
     }
 
+    /// Is this edition 2015?
     #[inline]
     pub fn is_rust_2015(self) -> bool {
         self.edition().is_rust_2015()
     }
 
+    /// Are we allowed to use features from the Rust 2018 edition?
     #[inline]
-    pub fn rust_2018(self) -> bool {
-        self.edition().rust_2018()
+    pub fn at_least_rust_2018(self) -> bool {
+        self.edition().at_least_rust_2018()
     }
 
+    /// Are we allowed to use features from the Rust 2021 edition?
     #[inline]
-    pub fn rust_2021(self) -> bool {
-        self.edition().rust_2021()
+    pub fn at_least_rust_2021(self) -> bool {
+        self.edition().at_least_rust_2021()
     }
 
+    /// Are we allowed to use features from the Rust 2024 edition?
     #[inline]
-    pub fn rust_2024(self) -> bool {
-        self.edition().rust_2024()
+    pub fn at_least_rust_2024(self) -> bool {
+        self.edition().at_least_rust_2024()
     }
 
     /// Returns the source callee.