about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs46
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs11
-rw-r--r--compiler/rustc_driver_impl/messages.ftl5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs38
-rw-r--r--compiler/rustc_driver_impl/src/session_diagnostics.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs3
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs15
-rw-r--r--compiler/rustc_lint/src/context/diagnostics.rs5
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp12
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs94
-rw-r--r--compiler/rustc_span/src/source_map.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs8
-rw-r--r--library/std/src/sys/pal/unsupported/process.rs150
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs3
-rw-r--r--src/tools/compiletest/src/header.rs1
-rw-r--r--src/tools/run-make-support/src/rustc.rs24
-rw-r--r--src/tools/run-make-support/src/rustdoc.rs18
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
-rw-r--r--tests/codegen/riscv-target-abi.rs20
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/cstart.c5
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs9
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/rmake.rs74
-rw-r--r--tests/run-make/exit-code/Makefile12
-rw-r--r--tests/run-make/exit-code/rmake.rs43
-rw-r--r--tests/rustdoc-ui/ice-bug-report-url.stderr2
-rw-r--r--tests/ui/consts/const-eval/const-eval-query-stack.stderr2
-rw-r--r--tests/ui/does-nothing.rs2
-rw-r--r--tests/ui/does-nothing.stderr9
-rw-r--r--tests/ui/panics/default-backtrace-ice.stderr2
-rw-r--r--tests/ui/track-diagnostics/track.stderr2
-rw-r--r--tests/ui/typeck/remove-semi-but-confused-char.rs11
-rw-r--r--tests/ui/typeck/remove-semi-but-confused-char.stderr25
36 files changed, 491 insertions, 203 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 093a985495c..01addc8127e 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -346,7 +346,7 @@ impl<'a> AstValidator<'a> {
             in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
             const_context_label: parent_constness,
             remove_const_sugg: (
-                self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span),
+                self.session.source_map().span_extend_while_whitespace(span),
                 match parent_constness {
                     Some(_) => rustc_errors::Applicability::MachineApplicable,
                     None => rustc_errors::Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index 06a681c24e6..e61af863dc0 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -608,7 +608,7 @@ pub(crate) fn run_pass_manager(
             "LTOPostLink".as_ptr().cast(),
             11,
         ) {
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 module.module_llvm.llmod(),
                 llvm::LLVMModFlagBehavior::Error,
                 c"LTOPostLink".as_ptr().cast(),
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index df9f066e58a..d32baa6dc02 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -180,13 +180,13 @@ pub unsafe fn create_module<'ll>(
     // to ensure intrinsic calls don't use it.
     if !sess.needs_plt() {
         let avoid_plt = c"RtLibUseGOT".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
+        llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
     }
 
     // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
     if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
         let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Override,
             canonical_jump_tables,
@@ -197,7 +197,7 @@ pub unsafe fn create_module<'ll>(
     // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
     if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
         let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Override,
             enable_split_lto_unit,
@@ -208,7 +208,7 @@ pub unsafe fn create_module<'ll>(
     // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
     if sess.is_sanitizer_kcfi_enabled() {
         let kcfi = c"kcfi".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
+        llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
@@ -217,7 +217,7 @@ pub unsafe fn create_module<'ll>(
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
                 // Set `cfguard=1` module flag to emit metadata only.
-                llvm::LLVMRustAddModuleFlag(
+                llvm::LLVMRustAddModuleFlagU32(
                     llmod,
                     llvm::LLVMModFlagBehavior::Warning,
                     c"cfguard".as_ptr() as *const _,
@@ -226,7 +226,7 @@ pub unsafe fn create_module<'ll>(
             }
             CFGuard::Checks => {
                 // Set `cfguard=2` module flag to emit metadata and checks.
-                llvm::LLVMRustAddModuleFlag(
+                llvm::LLVMRustAddModuleFlagU32(
                     llmod,
                     llvm::LLVMModFlagBehavior::Warning,
                     c"cfguard".as_ptr() as *const _,
@@ -238,26 +238,26 @@ pub unsafe fn create_module<'ll>(
 
     if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection {
         if sess.target.arch == "aarch64" {
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 llmod,
                 llvm::LLVMModFlagBehavior::Min,
                 c"branch-target-enforcement".as_ptr().cast(),
                 bti.into(),
             );
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 llmod,
                 llvm::LLVMModFlagBehavior::Min,
                 c"sign-return-address".as_ptr().cast(),
                 pac_ret.is_some().into(),
             );
             let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 llmod,
                 llvm::LLVMModFlagBehavior::Min,
                 c"sign-return-address-all".as_ptr().cast(),
                 pac_opts.leaf.into(),
             );
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 llmod,
                 llvm::LLVMModFlagBehavior::Min,
                 c"sign-return-address-with-bkey".as_ptr().cast(),
@@ -273,7 +273,7 @@ pub unsafe fn create_module<'ll>(
 
     // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
     if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Override,
             c"cf-protection-branch".as_ptr().cast(),
@@ -281,7 +281,7 @@ pub unsafe fn create_module<'ll>(
         )
     }
     if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection {
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Override,
             c"cf-protection-return".as_ptr().cast(),
@@ -290,7 +290,7 @@ pub unsafe fn create_module<'ll>(
     }
 
     if sess.opts.unstable_opts.virtual_function_elimination {
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Error,
             c"Virtual Function Elim".as_ptr().cast(),
@@ -300,7 +300,7 @@ pub unsafe fn create_module<'ll>(
 
     // Set module flag to enable Windows EHCont Guard (/guard:ehcont).
     if sess.opts.unstable_opts.ehcont_guard {
-        llvm::LLVMRustAddModuleFlag(
+        llvm::LLVMRustAddModuleFlagU32(
             llmod,
             llvm::LLVMModFlagBehavior::Warning,
             c"ehcontguard".as_ptr() as *const _,
@@ -326,6 +326,22 @@ pub unsafe fn create_module<'ll>(
         llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1),
     );
 
+    // Emit RISC-V specific target-abi metadata
+    // to workaround lld as the LTO plugin not
+    // correctly setting target-abi for the LTO object
+    // FIXME: https://github.com/llvm/llvm-project/issues/50591
+    // If llvm_abiname is empty, emit nothing.
+    let llvm_abiname = &sess.target.options.llvm_abiname;
+    if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() {
+        llvm::LLVMRustAddModuleFlagString(
+            llmod,
+            llvm::LLVMModFlagBehavior::Error,
+            c"target-abi".as_ptr(),
+            llvm_abiname.as_ptr().cast(),
+            llvm_abiname.len(),
+        );
+    }
+
     // Add module flags specified via -Z llvm_module_flag
     for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag {
         let key = format!("{key}\0");
@@ -341,7 +357,7 @@ pub unsafe fn create_module<'ll>(
             // We already checked this during option parsing
             _ => unreachable!(),
         };
-        llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value)
+        llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value)
     }
 
     llmod
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index d3a851b40c0..4fdaa59e0e5 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -110,7 +110,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
                     .unstable_opts
                     .dwarf_version
                     .unwrap_or(sess.target.default_dwarf_version);
-                llvm::LLVMRustAddModuleFlag(
+                llvm::LLVMRustAddModuleFlagU32(
                     self.llmod,
                     llvm::LLVMModFlagBehavior::Warning,
                     c"Dwarf Version".as_ptr().cast(),
@@ -118,7 +118,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
                 );
             } else {
                 // Indicate that we want CodeView debug information on MSVC
-                llvm::LLVMRustAddModuleFlag(
+                llvm::LLVMRustAddModuleFlagU32(
                     self.llmod,
                     llvm::LLVMModFlagBehavior::Warning,
                     c"CodeView".as_ptr().cast(),
@@ -127,7 +127,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
             }
 
             // Prevent bitcode readers from deleting the debug info.
-            llvm::LLVMRustAddModuleFlag(
+            llvm::LLVMRustAddModuleFlagU32(
                 self.llmod,
                 llvm::LLVMModFlagBehavior::Warning,
                 c"Debug Info Version".as_ptr().cast(),
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 284bc74d5c4..5509baaa3e9 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -1801,12 +1801,21 @@ extern "C" {
     ///
     /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
     /// "compatible" means depends on the merge behaviors involved.
-    pub fn LLVMRustAddModuleFlag(
+    pub fn LLVMRustAddModuleFlagU32(
         M: &Module,
         merge_behavior: LLVMModFlagBehavior,
         name: *const c_char,
         value: u32,
     );
+
+    pub fn LLVMRustAddModuleFlagString(
+        M: &Module,
+        merge_behavior: LLVMModFlagBehavior,
+        name: *const c_char,
+        value: *const c_char,
+        value_len: size_t,
+    );
+
     pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool;
 
     pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>;
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index 62391daecd0..5b39248302e 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -1,10 +1,7 @@
 driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
 driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
 driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly
-driver_impl_ice_bug_report_outdated =
-    it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the meantime
-    .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists
-    .url = if the problem still persists, we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_bug_report_update_note = please make sure that you have updated to the latest nightly
 driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
 
 driver_impl_ice_flags = compiler flags: {$flags}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b4007aeb8d7..1f44621736c 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -61,7 +61,7 @@ use std::str;
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, OnceLock};
 use std::time::{Instant, SystemTime};
-use time::{Date, OffsetDateTime, Time};
+use time::OffsetDateTime;
 
 #[allow(unused_macros)]
 macro do_not_use_print($($t:tt)*) {
@@ -1385,9 +1385,6 @@ pub fn install_ice_hook(
     using_internal_features
 }
 
-const DATE_FORMAT: &[time::format_description::FormatItem<'static>] =
-    &time::macros::format_description!("[year]-[month]-[day]");
-
 /// Prints the ICE message, including query stack, but without backtrace.
 ///
 /// The message will point the user at `bug_report_url` to report the ICE.
@@ -1416,33 +1413,14 @@ fn report_ice(
         dcx.emit_err(session_diagnostics::Ice);
     }
 
-    use time::ext::NumericalDuration;
-
-    // Try to hint user to update nightly if applicable when reporting an ICE.
-    // Attempt to calculate when current version was released, and add 12 hours
-    // as buffer. If the current version's release timestamp is older than
-    // the system's current time + 24 hours + 12 hours buffer if we're on
-    // nightly.
-    if let Some("nightly") = option_env!("CFG_RELEASE_CHANNEL")
-        && let Some(version) = option_env!("CFG_VERSION")
-        && let Some(ver_date_str) = option_env!("CFG_VER_DATE")
-        && let Ok(ver_date) = Date::parse(&ver_date_str, DATE_FORMAT)
-        && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT)
-        && let system_datetime = OffsetDateTime::from(SystemTime::now())
-        && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime)
-        && !using_internal_features.load(std::sync::atomic::Ordering::Relaxed)
-    {
-        dcx.emit_note(session_diagnostics::IceBugReportOutdated {
-            version,
-            bug_report_url,
-            note_update: (),
-            note_url: (),
-        });
+    if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) {
+        dcx.emit_note(session_diagnostics::IceBugReportInternalFeature);
     } else {
-        if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) {
-            dcx.emit_note(session_diagnostics::IceBugReportInternalFeature);
-        } else {
-            dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+        dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+
+        // Only emit update nightly hint for users on nightly builds.
+        if rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() {
+            dcx.emit_note(session_diagnostics::UpdateNightlyNote);
         }
     }
 
diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs
index 62d0da62d2a..1a9683e840a 100644
--- a/compiler/rustc_driver_impl/src/session_diagnostics.rs
+++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs
@@ -43,19 +43,12 @@ pub(crate) struct IceBugReport<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(driver_impl_ice_bug_report_internal_feature)]
-pub(crate) struct IceBugReportInternalFeature;
+#[diag(driver_impl_ice_bug_report_update_note)]
+pub(crate) struct UpdateNightlyNote;
 
 #[derive(Diagnostic)]
-#[diag(driver_impl_ice_bug_report_outdated)]
-pub(crate) struct IceBugReportOutdated<'a> {
-    pub version: &'a str,
-    pub bug_report_url: &'a str,
-    #[note(driver_impl_update)]
-    pub note_update: (),
-    #[note(driver_impl_url)]
-    pub note_url: (),
-}
+#[diag(driver_impl_ice_bug_report_internal_feature)]
+pub(crate) struct IceBugReportInternalFeature;
 
 #[derive(Diagnostic)]
 #[diag(driver_impl_ice_version)]
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index d3df3dd3885..7a1a2c498aa 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -2023,8 +2023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .tcx
                 .sess
                 .source_map()
-                .span_extend_while(range_start.span, |c| c.is_whitespace())
-                .unwrap_or(range_start.span)
+                .span_extend_while_whitespace(range_start.span)
                 .shrink_to_hi()
                 .to(range_end.span);
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 9a05fb1c30f..7855031e705 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -15,7 +15,7 @@ use rustc_middle::traits::{
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, Span};
 
 use crate::errors::{
     ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
@@ -763,8 +763,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span);
             self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)?
         } else {
-            last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1))
+            self.tcx
+                .sess
+                .source_map()
+                .span_extend_while_whitespace(last_expr.span)
+                .shrink_to_hi()
+                .with_hi(last_stmt.span.hi())
         };
+
         Some((span, needs_box))
     }
 
@@ -867,10 +873,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         format!(" {ident} ")
                     };
                     let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi();
-                    (
-                        sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span),
-                        sugg,
-                    )
+                    (sm.span_extend_while_whitespace(left_span), sugg)
                 };
                 Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident })
             }
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index e2010ab3830..16e3b8c11c1 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -215,10 +215,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di
             if let Some(deletion_span) = deletion_span {
                 let msg = "elide the single-use lifetime";
                 let (use_span, replace_lt) = if elide {
-                    let use_span = sess
-                        .source_map()
-                        .span_extend_while(use_span, char::is_whitespace)
-                        .unwrap_or(use_span);
+                    let use_span = sess.source_map().span_extend_while_whitespace(use_span);
                     (use_span, String::new())
                 } else {
                     (use_span, "'_".to_owned())
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index a6894a7e089..37c2da4c23a 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -817,7 +817,7 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; }
 
 extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; }
 
-extern "C" void LLVMRustAddModuleFlag(
+extern "C" void LLVMRustAddModuleFlagU32(
     LLVMModuleRef M,
     Module::ModFlagBehavior MergeBehavior,
     const char *Name,
@@ -825,6 +825,16 @@ extern "C" void LLVMRustAddModuleFlag(
   unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
 }
 
+extern "C" void LLVMRustAddModuleFlagString(
+    LLVMModuleRef M,
+    Module::ModFlagBehavior MergeBehavior,
+    const char *Name,
+    const char *Value,
+    size_t ValueLen) {
+  unwrap(M)->addModuleFlag(MergeBehavior, Name,
+    MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen)));
+}
+
 extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name,
                                       size_t Len) {
   return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr;
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index d6ec7d64926..ccb229616e8 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -126,59 +126,33 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
 
         let mut field_remapping = UnordMap::default();
 
-        // One parent capture may correspond to several child captures if we end up
-        // refining the set of captures via edition-2021 precise captures. We want to
-        // match up any number of child captures with one parent capture, so we keep
-        // peeking off this `Peekable` until the child doesn't match anymore.
-        let mut parent_captures =
-            tcx.closure_captures(parent_def_id).iter().copied().enumerate().peekable();
-        // Make sure we use every field at least once, b/c why are we capturing something
-        // if it's not used in the inner coroutine.
-        let mut field_used_at_least_once = false;
-
-        for (child_field_idx, child_capture) in tcx
+        let mut child_captures = tcx
             .closure_captures(coroutine_def_id)
             .iter()
             .copied()
             // By construction we capture all the args first.
             .skip(num_args)
             .enumerate()
-        {
-            loop {
-                let Some(&(parent_field_idx, parent_capture)) = parent_captures.peek() else {
-                    bug!("we ran out of parent captures!")
-                };
+            .peekable();
 
-                let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
-                    bug!("expected capture to be an upvar");
-                };
-                let PlaceBase::Upvar(child_base) = child_capture.place.base else {
-                    bug!("expected capture to be an upvar");
-                };
+        // One parent capture may correspond to several child captures if we end up
+        // refining the set of captures via edition-2021 precise captures. We want to
+        // match up any number of child captures with one parent capture, so we keep
+        // peeking off this `Peekable` until the child doesn't match anymore.
+        for (parent_field_idx, parent_capture) in
+            tcx.closure_captures(parent_def_id).iter().copied().enumerate()
+        {
+            // Make sure we use every field at least once, b/c why are we capturing something
+            // if it's not used in the inner coroutine.
+            let mut field_used_at_least_once = false;
 
-                assert!(
-                    child_capture.place.projections.len() >= parent_capture.place.projections.len()
-                );
-                // A parent matches a child they share the same prefix of projections.
-                // The child may have more, if it is capturing sub-fields out of
-                // something that is captured by-move in the parent closure.
-                if parent_base.var_path.hir_id != child_base.var_path.hir_id
-                    || !std::iter::zip(
-                        &child_capture.place.projections,
-                        &parent_capture.place.projections,
-                    )
-                    .all(|(child, parent)| child.kind == parent.kind)
-                {
-                    // Make sure the field was used at least once.
-                    assert!(
-                        field_used_at_least_once,
-                        "we captured {parent_capture:#?} but it was not used in the child coroutine?"
-                    );
-                    field_used_at_least_once = false;
-                    // Skip this field.
-                    let _ = parent_captures.next().unwrap();
-                    continue;
-                }
+            // A parent matches a child if they share the same prefix of projections.
+            // The child may have more, if it is capturing sub-fields out of
+            // something that is captured by-move in the parent closure.
+            while child_captures.peek().map_or(false, |(_, child_capture)| {
+                child_prefix_matches_parent_projections(parent_capture, child_capture)
+            }) {
+                let (child_field_idx, child_capture) = child_captures.next().unwrap();
 
                 // Store this set of additional projections (fields and derefs).
                 // We need to re-apply them later.
@@ -221,15 +195,15 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
                 );
 
                 field_used_at_least_once = true;
-                break;
             }
-        }
 
-        // Pop the last parent capture
-        if field_used_at_least_once {
-            let _ = parent_captures.next().unwrap();
+            // Make sure the field was used at least once.
+            assert!(
+                field_used_at_least_once,
+                "we captured {parent_capture:#?} but it was not used in the child coroutine?"
+            );
         }
-        assert_eq!(parent_captures.next(), None, "leftover parent captures?");
+        assert_eq!(child_captures.next(), None, "leftover child captures?");
 
         if coroutine_kind == ty::ClosureKind::FnOnce {
             assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
@@ -251,6 +225,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
         let mut by_move_body = body.clone();
         MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body);
         dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(()));
+        // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body.
         by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim {
             coroutine_def_id: coroutine_def_id.to_def_id(),
         });
@@ -258,6 +233,23 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
     }
 }
 
+fn child_prefix_matches_parent_projections(
+    parent_capture: &ty::CapturedPlace<'_>,
+    child_capture: &ty::CapturedPlace<'_>,
+) -> bool {
+    let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+    let PlaceBase::Upvar(child_base) = child_capture.place.base else {
+        bug!("expected capture to be an upvar");
+    };
+
+    assert!(child_capture.place.projections.len() >= parent_capture.place.projections.len());
+    parent_base.var_path.hir_id == child_base.var_path.hir_id
+        && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections)
+            .all(|(child, parent)| child.kind == parent.kind)
+}
+
 struct MakeByMoveBody<'tcx> {
     tcx: TyCtxt<'tcx>,
     field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>,
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 770624d331d..f721a04d6b9 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -654,6 +654,12 @@ impl SourceMap {
         })
     }
 
+    /// Extends the span to include any trailing whitespace, or returns the original
+    /// span if a `SpanSnippetError` was encountered.
+    pub fn span_extend_while_whitespace(&self, span: Span) -> Span {
+        self.span_extend_while(span, char::is_whitespace).unwrap_or(span)
+    }
+
     /// Extends the given `Span` to previous character while the previous character matches the predicate
     pub fn span_extend_prev_while(
         &self,
@@ -1034,12 +1040,9 @@ impl SourceMap {
     /// // ^^^^^^ input
     /// ```
     pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> {
-        let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?;
-        let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?));
-        if self.span_to_snippet(span).as_deref() != Ok(";") {
-            return None;
-        }
-        Some(span)
+        let span = self.span_extend_while_whitespace(mac_call);
+        let span = self.next_point(span);
+        if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None }
     }
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index af90372b97c..2067956d0f5 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1592,8 +1592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     .tcx
                     .sess
                     .source_map()
-                    .span_extend_while(expr_span, char::is_whitespace)
-                    .unwrap_or(expr_span)
+                    .span_extend_while_whitespace(expr_span)
                     .shrink_to_hi()
                     .to(await_expr.span.shrink_to_hi());
                 err.span_suggestion(
@@ -4851,10 +4850,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
     let hir::IsAsync::Async(async_span) = sig.header.asyncness else {
         return None;
     };
-    let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace())
-    else {
-        return None;
-    };
+    let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
 
     let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
     let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else {
diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs
index 6a989dd3e76..2445d9073db 100644
--- a/library/std/src/sys/pal/unsupported/process.rs
+++ b/library/std/src/sys/pal/unsupported/process.rs
@@ -1,7 +1,6 @@
-use crate::ffi::OsStr;
+use crate::ffi::{OsStr, OsString};
 use crate::fmt;
 use crate::io;
-use crate::marker::PhantomData;
 use crate::num::NonZero;
 use crate::path::Path;
 use crate::sys::fs::File;
@@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey;
 ////////////////////////////////////////////////////////////////////////////////
 
 pub struct Command {
+    program: OsString,
+    args: Vec<OsString>,
     env: CommandEnv,
+
+    cwd: Option<OsString>,
+    stdin: Option<Stdio>,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
 }
 
 // passed back to std::process with the pipes connected to the child, if any
@@ -27,39 +33,62 @@ pub struct StdioPipes {
     pub stderr: Option<AnonPipe>,
 }
 
-// FIXME: This should be a unit struct, so we can always construct it
-// The value here should be never used, since we cannot spawn processes.
+#[derive(Debug)]
 pub enum Stdio {
     Inherit,
     Null,
     MakePipe,
+    ParentStdout,
+    ParentStderr,
+    #[allow(dead_code)] // This variant exists only for the Debug impl
+    InheritFile(File),
 }
 
 impl Command {
-    pub fn new(_program: &OsStr) -> Command {
-        Command { env: Default::default() }
+    pub fn new(program: &OsStr) -> Command {
+        Command {
+            program: program.to_owned(),
+            args: vec![program.to_owned()],
+            env: Default::default(),
+            cwd: None,
+            stdin: None,
+            stdout: None,
+            stderr: None,
+        }
     }
 
-    pub fn arg(&mut self, _arg: &OsStr) {}
+    pub fn arg(&mut self, arg: &OsStr) {
+        self.args.push(arg.to_owned());
+    }
 
     pub fn env_mut(&mut self) -> &mut CommandEnv {
         &mut self.env
     }
 
-    pub fn cwd(&mut self, _dir: &OsStr) {}
+    pub fn cwd(&mut self, dir: &OsStr) {
+        self.cwd = Some(dir.to_owned());
+    }
 
-    pub fn stdin(&mut self, _stdin: Stdio) {}
+    pub fn stdin(&mut self, stdin: Stdio) {
+        self.stdin = Some(stdin);
+    }
 
-    pub fn stdout(&mut self, _stdout: Stdio) {}
+    pub fn stdout(&mut self, stdout: Stdio) {
+        self.stdout = Some(stdout);
+    }
 
-    pub fn stderr(&mut self, _stderr: Stdio) {}
+    pub fn stderr(&mut self, stderr: Stdio) {
+        self.stderr = Some(stderr);
+    }
 
     pub fn get_program(&self) -> &OsStr {
-        panic!("unsupported")
+        &self.program
     }
 
     pub fn get_args(&self) -> CommandArgs<'_> {
-        CommandArgs { _p: PhantomData }
+        let mut iter = self.args.iter();
+        iter.next();
+        CommandArgs { iter }
     }
 
     pub fn get_envs(&self) -> CommandEnvs<'_> {
@@ -67,7 +96,7 @@ impl Command {
     }
 
     pub fn get_current_dir(&self) -> Option<&Path> {
-        None
+        self.cwd.as_ref().map(|cs| Path::new(cs))
     }
 
     pub fn spawn(
@@ -91,31 +120,83 @@ impl From<AnonPipe> for Stdio {
 
 impl From<io::Stdout> for Stdio {
     fn from(_: io::Stdout) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
+        Stdio::ParentStdout
     }
 }
 
 impl From<io::Stderr> for Stdio {
     fn from(_: io::Stderr) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
+        Stdio::ParentStderr
     }
 }
 
 impl From<File> for Stdio {
-    fn from(_file: File) -> Stdio {
-        // FIXME: This is wrong.
-        // Instead, the Stdio we have here should be a unit struct.
-        panic!("unsupported")
+    fn from(file: File) -> Stdio {
+        Stdio::InheritFile(file)
     }
 }
 
 impl fmt::Debug for Command {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
+    // show all attributes
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if f.alternate() {
+            let mut debug_command = f.debug_struct("Command");
+            debug_command.field("program", &self.program).field("args", &self.args);
+            if !self.env.is_unchanged() {
+                debug_command.field("env", &self.env);
+            }
+
+            if self.cwd.is_some() {
+                debug_command.field("cwd", &self.cwd);
+            }
+
+            if self.stdin.is_some() {
+                debug_command.field("stdin", &self.stdin);
+            }
+            if self.stdout.is_some() {
+                debug_command.field("stdout", &self.stdout);
+            }
+            if self.stderr.is_some() {
+                debug_command.field("stderr", &self.stderr);
+            }
+
+            debug_command.finish()
+        } else {
+            if let Some(ref cwd) = self.cwd {
+                write!(f, "cd {cwd:?} && ")?;
+            }
+            if self.env.does_clear() {
+                write!(f, "env -i ")?;
+                // Altered env vars will be printed next, that should exactly work as expected.
+            } else {
+                // Removed env vars need the command to be wrapped in `env`.
+                let mut any_removed = false;
+                for (key, value_opt) in self.get_envs() {
+                    if value_opt.is_none() {
+                        if !any_removed {
+                            write!(f, "env ")?;
+                            any_removed = true;
+                        }
+                        write!(f, "-u {} ", key.to_string_lossy())?;
+                    }
+                }
+            }
+            // Altered env vars can just be added in front of the program.
+            for (key, value_opt) in self.get_envs() {
+                if let Some(value) = value_opt {
+                    write!(f, "{}={value:?} ", key.to_string_lossy())?;
+                }
+            }
+            if self.program != self.args[0] {
+                write!(f, "[{:?}] ", self.program)?;
+            }
+            write!(f, "{:?}", self.args[0])?;
+
+            for arg in &self.args[1..] {
+                write!(f, " {:?}", arg)?;
+            }
+            Ok(())
+        }
     }
 }
 
@@ -217,23 +298,30 @@ impl Process {
 }
 
 pub struct CommandArgs<'a> {
-    _p: PhantomData<&'a ()>,
+    iter: crate::slice::Iter<'a, OsString>,
 }
 
 impl<'a> Iterator for CommandArgs<'a> {
     type Item = &'a OsStr;
     fn next(&mut self) -> Option<&'a OsStr> {
-        None
+        self.iter.next().map(|os| &**os)
     }
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (0, Some(0))
+        self.iter.size_hint()
     }
 }
 
-impl<'a> ExactSizeIterator for CommandArgs<'a> {}
+impl<'a> ExactSizeIterator for CommandArgs<'a> {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 impl<'a> fmt::Debug for CommandArgs<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().finish()
+        f.debug_list().entries(self.iter.clone()).finish()
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index a60a40a2a47..2bb63ec2b04 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -294,8 +294,7 @@ fn elision_suggestions(
                         let span = cx
                             .sess()
                             .source_map()
-                            .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace())
-                            .unwrap_or(usage.ident.span);
+                            .span_extend_while_whitespace(usage.ident.span);
 
                         (span, String::new())
                     },
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 626841cb1bd..ec944cb7fb4 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -819,6 +819,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-dynamic-linking",
     "needs-git-hash",
     "needs-llvm-components",
+    "needs-matching-clang",
     "needs-profiler-support",
     "needs-relocation-model-pic",
     "needs-run-enabled",
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index 217da36ccc7..5a5b008a7cb 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -86,6 +86,18 @@ impl Rustc {
         self
     }
 
+    /// This flag defers LTO optimizations to the linker.
+    pub fn linker_plugin_lto(&mut self, option: &str) -> &mut Self {
+        self.cmd.arg(format!("-Clinker-plugin-lto={option}"));
+        self
+    }
+
+    /// Specify what happens when the code panics.
+    pub fn panic(&mut self, option: &str) -> &mut Self {
+        self.cmd.arg(format!("-Cpanic={option}"));
+        self
+    }
+
     /// Specify number of codegen units
     pub fn codegen_units(&mut self, units: usize) -> &mut Self {
         self.cmd.arg(format!("-Ccodegen-units={units}"));
@@ -183,6 +195,18 @@ impl Rustc {
         output
     }
 
+    #[track_caller]
+    pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if output.status.code().unwrap() != code {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
+
     /// Inspect what the underlying [`Command`] is up to the current construction.
     pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self {
         f(&self.cmd);
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index 9607ff02f96..1fb4b589d76 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -1,4 +1,5 @@
 use std::env;
+use std::ffi::OsStr;
 use std::path::Path;
 use std::process::{Command, Output};
 
@@ -58,9 +59,8 @@ impl Rustdoc {
         self
     }
 
-    /// Fallback argument provider. Consider adding meaningfully named methods instead of using
-    /// this method.
-    pub fn arg(&mut self, arg: &str) -> &mut Self {
+    /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`.
+    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
         self.cmd.arg(arg);
         self
     }
@@ -77,4 +77,16 @@ impl Rustdoc {
         }
         output
     }
+
+    #[track_caller]
+    pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
+        let caller_location = std::panic::Location::caller();
+        let caller_line_number = caller_location.line();
+
+        let output = self.cmd.output().unwrap();
+        if output.status.code().unwrap() != code {
+            handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number);
+        }
+        output
+    }
 }
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index dfd30d79abc..3914feb3499 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -59,7 +59,6 @@ run-make/emit/Makefile
 run-make/env-dep-info/Makefile
 run-make/error-found-staticlib-instead-crate/Makefile
 run-make/error-writing-dependencies/Makefile
-run-make/exit-code/Makefile
 run-make/export-executable-symbols/Makefile
 run-make/extern-diff-internal-name/Makefile
 run-make/extern-flag-disambiguates/Makefile
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 05652541461..78de8c0537d 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -18,7 +18,7 @@ const ENTRY_LIMIT: usize = 900;
 // FIXME: The following limits should be reduced eventually.
 
 const ISSUES_ENTRY_LIMIT: usize = 1722;
-const ROOT_ENTRY_LIMIT: usize = 861;
+const ROOT_ENTRY_LIMIT: usize = 859;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs
new file mode 100644
index 00000000000..5d545af9c76
--- /dev/null
+++ b/tests/codegen/riscv-target-abi.rs
@@ -0,0 +1,20 @@
+//@ revisions:riscv64gc riscv32gc riscv32imac
+
+//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu
+//@[riscv64gc] needs-llvm-components: riscv
+// riscv64gc: !{i32 1, !"target-abi", !"lp64d"}
+
+//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl
+//@[riscv32gc] needs-llvm-components: riscv
+// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"}
+
+//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf
+//@[riscv32imac] needs-llvm-components: riscv
+// riscv32imac-NOT: !"target-abi"
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/cstart.c b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c
new file mode 100644
index 00000000000..660469b75a8
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c
@@ -0,0 +1,5 @@
+extern void hello();
+
+void _start() {
+    hello();
+}
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
new file mode 100644
index 00000000000..c31cf27f9ae
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
@@ -0,0 +1,9 @@
+#![allow(internal_features)]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn hello() {}
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
new file mode 100644
index 00000000000..2f13cf17169
--- /dev/null
+++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs
@@ -0,0 +1,74 @@
+//! Make sure that cross-language LTO works on riscv targets,
+//! which requires extra abi metadata to be emitted.
+//@ needs-matching-clang
+//@ needs-llvm-components riscv
+extern crate run_make_support;
+
+use run_make_support::{bin_name, rustc, tmp_dir};
+use std::{
+    env,
+    path::PathBuf,
+    process::{Command, Output},
+    str,
+};
+
+fn handle_failed_output(output: Output) {
+    eprintln!("output status: `{}`", output.status);
+    eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap());
+    eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap());
+    std::process::exit(1)
+}
+
+fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) {
+    eprintln!("Checking target {target}");
+    // Rust part
+    rustc()
+        .input("riscv-xlto.rs")
+        .crate_type("rlib")
+        .target(target)
+        .panic("abort")
+        .linker_plugin_lto("on")
+        .run();
+    // C part
+    let clang = env::var("CLANG").unwrap();
+    let mut cmd = Command::new(clang);
+    let executable = tmp_dir().join("riscv-xlto");
+    cmd.arg("-target")
+        .arg(clang_target)
+        .arg(format!("-march={carch}"))
+        .arg(format!("-flto=thin"))
+        .arg(format!("-fuse-ld=lld"))
+        .arg("-nostdlib")
+        .arg("-o")
+        .arg(&executable)
+        .arg("cstart.c")
+        .arg(tmp_dir().join("libriscv_xlto.rlib"));
+    eprintln!("{cmd:?}");
+    let output = cmd.output().unwrap();
+    if !output.status.success() {
+        handle_failed_output(output);
+    }
+    // Check that the built binary has correct float abi
+    let llvm_readobj =
+        PathBuf::from(env::var("LLVM_BIN_DIR").unwrap()).join(bin_name("llvm-readobj"));
+    let mut cmd = Command::new(llvm_readobj);
+    cmd.arg("--file-header").arg(executable);
+    eprintln!("{cmd:?}");
+    let output = cmd.output().unwrap();
+    if output.status.success() {
+        assert!(
+            !(is_double_float
+                ^ dbg!(str::from_utf8(&output.stdout).unwrap())
+                    .contains("EF_RISCV_FLOAT_ABI_DOUBLE"))
+        )
+    } else {
+        handle_failed_output(output);
+    }
+}
+
+fn main() {
+    check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true);
+    check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false);
+    check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false);
+    check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true);
+}
diff --git a/tests/run-make/exit-code/Makefile b/tests/run-make/exit-code/Makefile
deleted file mode 100644
index 155e5cd1123..00000000000
--- a/tests/run-make/exit-code/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) success.rs; [ $$? -eq 0 ]
-	$(RUSTC) --invalid-arg-foo; [ $$? -eq 1 ]
-	$(RUSTC) compile-error.rs; [ $$? -eq 1 ]
-	RUSTC_ICE=0 $(RUSTC) -Ztreat-err-as-bug compile-error.rs; [ $$? -eq 101 ]
-	$(RUSTDOC) -o $(TMPDIR)/exit-code success.rs; [ $$? -eq 0 ]
-	$(RUSTDOC) --invalid-arg-foo; [ $$? -eq 1 ]
-	$(RUSTDOC) compile-error.rs; [ $$? -eq 1 ]
-	$(RUSTDOC) lint-failure.rs; [ $$? -eq 1 ]
diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs
new file mode 100644
index 00000000000..f387626287e
--- /dev/null
+++ b/tests/run-make/exit-code/rmake.rs
@@ -0,0 +1,43 @@
+// Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations
+
+extern crate run_make_support;
+
+use run_make_support::{rustc, rustdoc, tmp_dir};
+
+fn main() {
+    rustc()
+        .arg("success.rs")
+        .run();
+
+    rustc()
+        .arg("--invalid-arg-foo")
+        .run_fail_assert_exit_code(1);
+
+    rustc()
+        .arg("compile-error.rs")
+        .run_fail_assert_exit_code(1);
+
+    rustc()
+        .env("RUSTC_ICE", "0")
+        .arg("-Ztreat-err-as-bug")
+        .arg("compile-error.rs")
+        .run_fail_assert_exit_code(101);
+
+    rustdoc()
+        .arg("success.rs")
+        .arg("-o")
+        .arg(tmp_dir().join("exit-code"))
+        .run();
+
+    rustdoc()
+        .arg("--invalid-arg-foo")
+        .run_fail_assert_exit_code(1);
+
+    rustdoc()
+        .arg("compile-error.rs")
+        .run_fail_assert_exit_code(1);
+
+    rustdoc()
+        .arg("lint-failure.rs")
+        .run_fail_assert_exit_code(1);
+}
diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr
index 06a52691310..66622a7654c 100644
--- a/tests/rustdoc-ui/ice-bug-report-url.stderr
+++ b/tests/rustdoc-ui/ice-bug-report-url.stderr
@@ -12,6 +12,8 @@ error: the compiler unexpectedly panicked. this is a bug.
 
 note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md
 
+note: please make sure that you have updated to the latest nightly
+
 note: rustc {version} running on {platform}
 
 query stack during panic:
diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr
index 96fd9ed5f04..0a28c5b80bf 100644
--- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr
+++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr
@@ -4,6 +4,8 @@ error: internal compiler error[E0080]: evaluation of constant value failed
 LL | const X: i32 = 1 / 0;
    |                ^^^^^ attempt to divide `1_i32` by zero
 
+note: please make sure that you have updated to the latest nightly
+
 query stack during panic:
 #0 [eval_to_allocation_raw] const-evaluating + checking `X`
 #1 [eval_to_const_value_raw] simplifying constant for the type system `X`
diff --git a/tests/ui/does-nothing.rs b/tests/ui/does-nothing.rs
deleted file mode 100644
index e4992e2cfd3..00000000000
--- a/tests/ui/does-nothing.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); }
-//~^ ERROR cannot find value `this_does_nothing_what_the` in this scope
diff --git a/tests/ui/does-nothing.stderr b/tests/ui/does-nothing.stderr
deleted file mode 100644
index d5ea3626e81..00000000000
--- a/tests/ui/does-nothing.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `this_does_nothing_what_the` in this scope
-  --> $DIR/does-nothing.rs:1:32
-   |
-LL | fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); }
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr
index 82b61e43f44..23b863568bc 100644
--- a/tests/ui/panics/default-backtrace-ice.stderr
+++ b/tests/ui/panics/default-backtrace-ice.stderr
@@ -20,6 +20,8 @@ error: the compiler unexpectedly panicked. this is a bug.
 
 
 
+
+
 query stack during panic:
 #0 [resolver_for_lowering_raw] getting the resolver for lowering
 end of query stack
diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr
index 54b1ea2764a..436f9ecf93d 100644
--- a/tests/ui/track-diagnostics/track.stderr
+++ b/tests/ui/track-diagnostics/track.stderr
@@ -30,6 +30,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
 
 note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md
 
+note: please make sure that you have updated to the latest nightly
+
 note: rustc $VERSION running on $TARGET
 
 note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics
diff --git a/tests/ui/typeck/remove-semi-but-confused-char.rs b/tests/ui/typeck/remove-semi-but-confused-char.rs
new file mode 100644
index 00000000000..ccc6f59344c
--- /dev/null
+++ b/tests/ui/typeck/remove-semi-but-confused-char.rs
@@ -0,0 +1,11 @@
+// Ensures our "remove semicolon" suggestion isn't hardcoded with a character width,
+// in case it was accidentally mixed up with a greek question mark.
+// issue: rust-lang/rust#123607
+
+pub fn square(num: i32) -> i32 {
+    //~^ ERROR mismatched types
+    num * num;
+    //~^ ERROR unknown start of token
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/remove-semi-but-confused-char.stderr b/tests/ui/typeck/remove-semi-but-confused-char.stderr
new file mode 100644
index 00000000000..2d0b53a60ce
--- /dev/null
+++ b/tests/ui/typeck/remove-semi-but-confused-char.stderr
@@ -0,0 +1,25 @@
+error: unknown start of token: \u{37e}
+  --> $DIR/remove-semi-but-confused-char.rs:7:14
+   |
+LL |     num * num;
+   |              ^
+   |
+help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not
+   |
+LL |     num * num;
+   |              ~
+
+error[E0308]: mismatched types
+  --> $DIR/remove-semi-but-confused-char.rs:5:28
+   |
+LL | pub fn square(num: i32) -> i32 {
+   |        ------              ^^^ expected `i32`, found `()`
+   |        |
+   |        implicitly returns `()` as its body has no tail or `return` expression
+LL |
+LL |     num * num;
+   |              - help: remove this semicolon to return this value
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.