about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-10 02:43:17 +0000
committerbors <bors@rust-lang.org>2024-04-10 02:43:17 +0000
commit1c77f7378e1894c3580046ba01791f2ed5a88ee3 (patch)
treeaeeddc1dc0c6cec37c21d4891ee03f8c5af20209 /compiler
parent93c131eba0fdcccc98d2fa52248765511cab93c5 (diff)
parentdf068dba0a3f2bf332079fbfa5b94d0249d40fec (diff)
downloadrust-1c77f7378e1894c3580046ba01791f2ed5a88ee3.tar.gz
rust-1c77f7378e1894c3580046ba01791f2ed5a88ee3.zip
Auto merge of #123708 - matthiaskrgr:rollup-uf9w1e9, r=matthiaskrgr
Rollup of 7 pull requests

Successful merges:

 - #121884 (Port exit-code run-make test to use rust)
 - #122200 (Unconditionally show update nightly hint on ICE)
 - #123568 (Clean up tests/ui by removing `does-nothing.rs`)
 - #123609 (Don't use bytepos offsets when computing semicolon span for removal)
 - #123612 (Set target-abi module flag for RISC-V targets)
 - #123633 (Store all args in the unsupported Command implementation)
 - #123668 (async closure coroutine by move body MirPass refactoring)

Failed merges:

 - #123701 (Only assert for child/parent projection compatibility AFTER checking that theyre coming from the same place)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-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
15 files changed, 135 insertions, 142 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 {