about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs13
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mono_item.rs2
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs4
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs2
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs165
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/initialized.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs4
-rw-r--r--compiler/rustc_pattern_analysis/src/constructor.rs2
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs6
-rw-r--r--compiler/rustc_resolve/src/imports.rs2
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs2
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs28
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs48
-rw-r--r--compiler/rustc_type_ir/src/const_kind.rs10
-rw-r--r--compiler/rustc_type_ir/src/region_kind.rs2
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs16
-rw-r--r--compiler/stable_mir/src/mir/pretty.rs10
-rw-r--r--config.example.toml1
-rw-r--r--library/std/Cargo.toml2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/pal/uefi/helpers.rs199
-rw-r--r--library/std/src/sys/pal/uefi/mod.rs1
-rw-r--r--library/std/src/sys/pal/uefi/process.rs689
-rw-r--r--library/std/src/thread/mod.rs74
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs2
-rw-r--r--src/bootstrap/src/lib.rs13
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs10
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/tarball.rs2
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/run-make/crate-hash-rustc-version/Makefile38
-rw-r--r--tests/run-make/crate-hash-rustc-version/rmake.rs57
-rw-r--r--tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.rs15
-rw-r--r--tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr25
-rw-r--r--tests/ui/error-codes/E0746.stderr9
-rw-r--r--tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr38
-rw-r--r--tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr5
-rw-r--r--tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr13
-rw-r--r--tests/ui/issues/issue-18107.stderr4
-rw-r--r--tests/ui/unsized/box-instead-of-dyn-fn.stderr4
-rw-r--r--tests/ui/unsized/issue-91801.stderr10
-rw-r--r--tests/ui/unsized/issue-91803.stderr4
53 files changed, 1296 insertions, 294 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index f7e4bba3712..a4fd00efe05 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -456,10 +456,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
                 if let Some(def_id) = def_id
                     && self.infcx.tcx.def_kind(def_id).is_fn_like()
                     && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
-                    && let ty::Param(_) =
-                        self.infcx.tcx.fn_sig(def_id).skip_binder().skip_binder().inputs()
-                            [pos + offset]
-                            .kind()
+                    && let Some(arg) = self
+                        .infcx
+                        .tcx
+                        .fn_sig(def_id)
+                        .skip_binder()
+                        .skip_binder()
+                        .inputs()
+                        .get(pos + offset)
+                    && let ty::Param(_) = arg.kind()
                 {
                     let place = &self.move_data.move_paths[mpi].place;
                     let ty = place.ty(self.body, self.infcx.tcx).ty;
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index fa0de6f9de5..ac5aaea561c 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -505,7 +505,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
                 let nop_inst = fx.bcx.ins().nop();
                 fx.add_comment(
                     nop_inst,
-                    format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]),
+                    format!("virtual call; self arg pass mode: {:?}", fn_abi.args[0]),
                 );
             }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8e07d128dbd..8c582fac0d8 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -759,7 +759,7 @@ fn link_natively(
     sess.dcx().abort_if_errors();
 
     // Invoke the system linker
-    info!("{:?}", &cmd);
+    info!("{cmd:?}");
     let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
     let unknown_arg_regex =
         Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
@@ -796,7 +796,7 @@ fn link_natively(
                     cmd.arg(arg);
                 }
             }
-            info!("{:?}", &cmd);
+            info!("{cmd:?}");
             continue;
         }
 
@@ -817,7 +817,7 @@ fn link_natively(
                     cmd.arg(arg);
                 }
             }
-            info!("{:?}", &cmd);
+            info!("{cmd:?}");
             continue;
         }
 
@@ -878,7 +878,7 @@ fn link_natively(
                     cmd.arg(arg);
                 }
             }
-            info!("{:?}", &cmd);
+            info!("{cmd:?}");
             continue;
         }
 
@@ -996,7 +996,7 @@ fn link_natively(
                 sess.dcx().emit_err(errors::UnableToExeLinker {
                     linker_path,
                     error: e,
-                    command_formatted: format!("{:?}", &cmd),
+                    command_formatted: format!("{cmd:?}"),
                 });
             }
 
@@ -1567,7 +1567,7 @@ fn print_native_static_libs(
                 sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts);
                 // Prefix for greppability
                 // Note: This must not be translated as tools are allowed to depend on this exact string.
-                sess.dcx().note(format!("native-static-libs: {}", &lib_args.join(" ")));
+                sess.dcx().note(format!("native-static-libs: {}", lib_args.join(" ")));
             }
         }
     }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 56a893738df..bfa4c683d56 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -328,7 +328,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             sym::link_section => {
                 if let Some(val) = attr.value_str() {
                     if val.as_str().bytes().any(|b| b == 0) {
-                        let msg = format!("illegal null byte in link_section value: `{}`", &val);
+                        let msg = format!("illegal null byte in link_section value: `{val}`");
                         tcx.dcx().span_err(attr.span, msg);
                     } else {
                         codegen_fn_attrs.link_section = Some(val);
@@ -726,7 +726,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
         if *ordinal <= u16::MAX as u128 {
             Some(ordinal.get() as u16)
         } else {
-            let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
+            let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`");
             tcx.dcx()
                 .struct_span_err(attr.span, msg)
                 .with_note("the value may not exceed `u16::MAX`")
diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs
index 0fbcb938d1a..559ec400577 100644
--- a/compiler/rustc_codegen_ssa/src/mono_item.rs
+++ b/compiler/rustc_codegen_ssa/src/mono_item.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
 
         let symbol_name = self.symbol_name(cx.tcx()).name;
 
-        debug!("symbol {}", &symbol_name);
+        debug!("symbol {symbol_name}");
 
         match *self {
             MonoItem::Static(def_id) => {
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 214b6587af3..68fdabd3529 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -253,7 +253,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
 
             for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
                 let snake_name = Ident::new(
-                    &format!("{}{}", &crate_prefix, &attr_name.replace('-', "_")),
+                    &format!("{crate_prefix}{}", attr_name.replace('-', "_")),
                     resource_str.span(),
                 );
                 if !previous_attrs.insert(snake_name.clone()) {
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 6426ad9dc18..10be69a9fbb 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -651,7 +651,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             self.path_segment.hir_id,
             num_params_to_take,
         );
-        debug!("suggested_args: {:?}", &suggested_args);
+        debug!("suggested_args: {suggested_args:?}");
 
         match self.angle_brackets {
             AngleBrackets::Missing => {
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index af08f50f655..d953736c28c 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -249,7 +249,7 @@ fn check_explicit_predicates<'tcx>(
     let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
 
     for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
-        debug!("outlives_predicate = {:?}", &outlives_predicate);
+        debug!("outlives_predicate = {outlives_predicate:?}");
 
         // Careful: If we are inferring the effects of a `dyn Trait<..>`
         // type, then when we look up the predicates for `Trait`,
@@ -289,12 +289,12 @@ fn check_explicit_predicates<'tcx>(
             && let GenericArgKind::Type(ty) = outlives_predicate.0.unpack()
             && ty.walk().any(|arg| arg == self_ty.into())
         {
-            debug!("skipping self ty = {:?}", &ty);
+            debug!("skipping self ty = {ty:?}");
             continue;
         }
 
         let predicate = explicit_predicates.rebind(*outlives_predicate).instantiate(tcx, args);
-        debug!("predicate = {:?}", &predicate);
+        debug!("predicate = {predicate:?}");
         insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 1cc7cf67ee3..9bb30780a6e 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1265,9 +1265,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         }
                         (
                             match parent_pred {
-                                None => format!("`{}`", &p),
+                                None => format!("`{p}`"),
                                 Some(parent_pred) => match format_pred(*parent_pred) {
-                                    None => format!("`{}`", &p),
+                                    None => format!("`{p}`"),
                                     Some((parent_p, _)) => {
                                         if !suggested
                                             && !suggested_bounds.contains(pred)
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index d1ccd158cf9..b113e81bd2d 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -112,7 +112,7 @@ pub fn report_unstable(
 ) {
     let msg = match reason {
         Some(r) => format!("use of unstable library feature '{feature}': {r}"),
-        None => format!("use of unstable library feature '{}'", &feature),
+        None => format!("use of unstable library feature '{feature}'"),
     };
 
     if is_soft {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 57cd2dc73c4..0e241663e18 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2627,7 +2627,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             self.prepare_region_info(value);
         }
 
-        debug!("self.used_region_names: {:?}", &self.used_region_names);
+        debug!("self.used_region_names: {:?}", self.used_region_names);
 
         let mut empty = true;
         let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
index 027e2703e98..831853b0b48 100644
--- a/compiler/rustc_middle/src/util/find_self_call.rs
+++ b/compiler/rustc_middle/src/util/find_self_call.rs
@@ -14,7 +14,7 @@ pub fn find_self_call<'tcx>(
     local: Local,
     block: BasicBlock,
 ) -> Option<(DefId, GenericArgsRef<'tcx>)> {
-    debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
+    debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
     if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
         &body[block].terminator
     {
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index b531a392efa..7f4a2e73d33 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2162,92 +2162,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         self.ascribe_types(block, ascriptions);
 
-        // rust-lang/rust#27282: The `autoref` business deserves some
-        // explanation here.
-        //
-        // The intent of the `autoref` flag is that when it is true,
-        // then any pattern bindings of type T will map to a `&T`
-        // within the context of the guard expression, but will
-        // continue to map to a `T` in the context of the arm body. To
-        // avoid surfacing this distinction in the user source code
-        // (which would be a severe change to the language and require
-        // far more revision to the compiler), when `autoref` is true,
-        // then any occurrence of the identifier in the guard
-        // expression will automatically get a deref op applied to it.
-        //
-        // So an input like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { foo if inspect(foo)
-        //     => feed(foo), ... }
-        // ```
-        //
-        // will be treated as if it were really something like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
-        //     => { let tmp2 = place; feed(tmp2) }, ... }
-        // ```
-        //
-        // And an input like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { ref mut foo if inspect(foo)
-        //     => feed(foo), ... }
-        // ```
-        //
-        // will be treated as if it were really something like:
-        //
-        // ```
-        // let place = Foo::new();
-        // match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
-        //     => { let tmp2 = &mut place; feed(tmp2) }, ... }
-        // ```
-        //
-        // In short, any pattern binding will always look like *some*
-        // kind of `&T` within the guard at least in terms of how the
-        // MIR-borrowck views it, and this will ensure that guard
-        // expressions cannot mutate their the match inputs via such
-        // bindings. (It also ensures that guard expressions can at
-        // most *copy* values from such bindings; non-Copy things
-        // cannot be moved via pattern bindings in guard expressions.)
-        //
-        // ----
-        //
-        // Implementation notes (under assumption `autoref` is true).
-        //
-        // To encode the distinction above, we must inject the
-        // temporaries `tmp1` and `tmp2`.
-        //
-        // There are two cases of interest: binding by-value, and binding by-ref.
-        //
-        // 1. Binding by-value: Things are simple.
-        //
-        //    * Establishing `tmp1` creates a reference into the
-        //      matched place. This code is emitted by
-        //      bind_matched_candidate_for_guard.
-        //
-        //    * `tmp2` is only initialized "lazily", after we have
-        //      checked the guard. Thus, the code that can trigger
-        //      moves out of the candidate can only fire after the
-        //      guard evaluated to true. This initialization code is
-        //      emitted by bind_matched_candidate_for_arm.
-        //
-        // 2. Binding by-reference: Things are tricky.
-        //
-        //    * Here, the guard expression wants a `&&` or `&&mut`
-        //      into the original input. This means we need to borrow
-        //      the reference that we create for the arm.
-        //    * So we eagerly create the reference for the arm and then take a
-        //      reference to that.
+        // Lower an instance of the arm guard (if present) for this candidate,
+        // and then perform bindings for the arm body.
         if let Some((arm, match_scope)) = arm_match_scope
             && let Some(guard) = arm.guard
         {
             let tcx = self.tcx;
 
+            // Bindings for guards require some extra handling to automatically
+            // insert implicit references/dereferences.
             self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
             let guard_frame = GuardFrame {
                 locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(),
@@ -2387,6 +2310,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
     }
 
+    /// Binding for guards is a bit different from binding for the arm body,
+    /// because an extra layer of implicit reference/dereference is added.
+    ///
+    /// The idea is that any pattern bindings of type T will map to a `&T` within
+    /// the context of the guard expression, but will continue to map to a `T`
+    /// in the context of the arm body. To avoid surfacing this distinction in
+    /// the user source code (which would be a severe change to the language and
+    /// require far more revision to the compiler), any occurrence of the
+    /// identifier in the guard expression will automatically get a deref op
+    /// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].)
+    ///
+    /// So an input like:
+    ///
+    /// ```ignore (illustrative)
+    /// let place = Foo::new();
+    /// match place { foo if inspect(foo)
+    ///     => feed(foo), ... }
+    /// ```
+    ///
+    /// will be treated as if it were really something like:
+    ///
+    /// ```ignore (illustrative)
+    /// let place = Foo::new();
+    /// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
+    ///     => { let tmp2 = place; feed(tmp2) }, ... }
+    /// ```
+    ///
+    /// And an input like:
+    ///
+    /// ```ignore (illustrative)
+    /// let place = Foo::new();
+    /// match place { ref mut foo if inspect(foo)
+    ///     => feed(foo), ... }
+    /// ```
+    ///
+    /// will be treated as if it were really something like:
+    ///
+    /// ```ignore (illustrative)
+    /// let place = Foo::new();
+    /// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
+    ///     => { let tmp2 = &mut place; feed(tmp2) }, ... }
+    /// ```
+    /// ---
+    ///
+    /// ## Implementation notes
+    ///
+    /// To encode the distinction above, we must inject the
+    /// temporaries `tmp1` and `tmp2`.
+    ///
+    /// There are two cases of interest: binding by-value, and binding by-ref.
+    ///
+    /// 1. Binding by-value: Things are simple.
+    ///
+    ///    * Establishing `tmp1` creates a reference into the
+    ///      matched place. This code is emitted by
+    ///      [`Self::bind_matched_candidate_for_guard`].
+    ///
+    ///    * `tmp2` is only initialized "lazily", after we have
+    ///      checked the guard. Thus, the code that can trigger
+    ///      moves out of the candidate can only fire after the
+    ///      guard evaluated to true. This initialization code is
+    ///      emitted by [`Self::bind_matched_candidate_for_arm_body`].
+    ///
+    /// 2. Binding by-reference: Things are tricky.
+    ///
+    ///    * Here, the guard expression wants a `&&` or `&&mut`
+    ///      into the original input. This means we need to borrow
+    ///      the reference that we create for the arm.
+    ///    * So we eagerly create the reference for the arm and then take a
+    ///      reference to that.
+    ///
+    /// ---
+    ///
+    /// See these PRs for some historical context:
+    /// - <https://github.com/rust-lang/rust/pull/49870> (introduction of autoref)
+    /// - <https://github.com/rust-lang/rust/pull/59114> (always use autoref)
     fn bind_matched_candidate_for_guard<'b>(
         &mut self,
         block: BasicBlock,
@@ -2418,10 +2417,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             );
             match binding.binding_mode.0 {
                 ByRef::No => {
+                    // The arm binding will be by value, so for the guard binding
+                    // just take a shared reference to the matched place.
                     let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
                     self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
                 }
                 ByRef::Yes(mutbl) => {
+                    // The arm binding will be by reference, so eagerly create it now.
                     let value_for_arm = self.storage_live_binding(
                         block,
                         binding.var_id,
@@ -2433,6 +2435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let rvalue =
                         Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
                     self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
+                    // For the guard binding, take a shared reference to that reference.
                     let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
                     self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
                 }
diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
index a9bceeccdce..d44da42416d 100644
--- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs
@@ -688,7 +688,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> {
         let init_loc_map = &move_data.init_loc_map;
         let rev_lookup = &move_data.rev_lookup;
 
-        debug!("initializes move_indexes {:?}", &init_loc_map[location]);
+        debug!("initializes move_indexes {:?}", init_loc_map[location]);
         trans.gen_all(init_loc_map[location].iter().copied());
 
         if let mir::StatementKind::StorageDead(local) = stmt.kind {
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 08dba1de500..60230bea02e 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -102,7 +102,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 | StatementKind::Nop => (),
 
                 StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
-                    bug!("{:?} not found in this MIR phase!", &statement.kind)
+                    bug!("{:?} not found in this MIR phase!", statement.kind)
                 }
             }
         }
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 9edb8bcee6e..40c0c723d25 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -106,11 +106,11 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
             let parent = BasicBlock::from_usize(i);
             let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
 
-            if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) {
+            if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {opt_data:?}")) {
                 break;
             }
 
-            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data);
+            trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
 
             should_cleanup = true;
 
diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs
index fb103705475..f3e8e547066 100644
--- a/compiler/rustc_pattern_analysis/src/constructor.rs
+++ b/compiler/rustc_pattern_analysis/src/constructor.rs
@@ -904,7 +904,7 @@ impl<Cx: PatCx> Constructor<Cx> {
             // be careful to detect strings here. However a string literal pattern will never
             // be reported as a non-exhaustiveness witness, so we can ignore this issue.
             Ref => {
-                write!(f, "&{:?}", &fields.next().unwrap())?;
+                write!(f, "&{:?}", fields.next().unwrap())?;
             }
             Slice(slice) => {
                 write!(f, "[")?;
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 7c0405c87e0..bf7972e392c 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     BuiltinLintDiag::AmbiguousGlobImports { diag },
                 );
             } else {
-                let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", &diag.msg);
+                let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg);
                 report_ambiguity_error(&mut err, diag);
                 err.emit();
             }
@@ -798,7 +798,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
             ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
                 let mut err =
-                    struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label);
+                    struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
                 err.span_label(span, label);
 
                 if let Some((suggestions, msg, applicability)) = suggestion {
@@ -2893,7 +2893,7 @@ fn show_candidates(
                     ""
                 };
                 candidate.0 =
-                    format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0);
+                    format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
             }
 
             match mode {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3896fe4c4fa..d05326ee311 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -694,7 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             .collect::<Vec<_>>();
         let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
 
-        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{}", &msg);
+        let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{msg}");
 
         if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
             diag.note(note.clone());
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 59460815321..4c49c15c472 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -339,7 +339,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
         }
     }
 
-    debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
+    debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}");
 
     let stripped_path = stripped_segments.join("::");
 
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index f998fd599b7..190ea443189 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -238,12 +238,12 @@ fn encode_predicate<'tcx>(
     match predicate.as_ref().skip_binder() {
         ty::ExistentialPredicate::Trait(trait_ref) => {
             let name = encode_ty_name(tcx, trait_ref.def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
             s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options));
         }
         ty::ExistentialPredicate::Projection(projection) => {
             let name = encode_ty_name(tcx, projection.def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
             s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options));
             match projection.term.unpack() {
                 TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
@@ -258,7 +258,7 @@ fn encode_predicate<'tcx>(
         }
         ty::ExistentialPredicate::AutoTrait(def_id) => {
             let name = encode_ty_name(tcx, *def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
         }
     };
     compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
@@ -416,7 +416,7 @@ pub fn encode_ty<'tcx>(
             // A<array-length><element-type>
             let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
             let mut s = String::from("A");
-            let _ = write!(s, "{}", &len);
+            let _ = write!(s, "{len}");
             s.push_str(&encode_ty(tcx, *ty0, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -492,13 +492,13 @@ pub fn encode_ty<'tcx>(
                 // calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
                 // <name> is <unscoped-name>.
                 let name = tcx.item_name(def_id).to_string();
-                let _ = write!(s, "{}{}", name.len(), &name);
+                let _ = write!(s, "{}{}", name.len(), name);
                 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             } else {
                 // u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
                 // <subst>, as vendor extended type.
                 let name = encode_ty_name(tcx, def_id);
-                let _ = write!(s, "u{}{}", name.len(), &name);
+                let _ = write!(s, "u{}{}", name.len(), name);
                 s.push_str(&encode_args(tcx, args, def_id, false, dict, options));
                 compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             }
@@ -530,7 +530,7 @@ pub fn encode_ty<'tcx>(
                 }
             } else {
                 let name = tcx.item_name(*def_id).to_string();
-                let _ = write!(s, "{}{}", name.len(), &name);
+                let _ = write!(s, "{}{}", name.len(), name);
             }
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -542,7 +542,7 @@ pub fn encode_ty<'tcx>(
             // as vendor extended type.
             let mut s = String::new();
             let name = encode_ty_name(tcx, *def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
             s.push_str(&encode_args(tcx, args, *def_id, false, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -553,7 +553,7 @@ pub fn encode_ty<'tcx>(
             // as vendor extended type.
             let mut s = String::new();
             let name = encode_ty_name(tcx, *def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
             let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
             s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options));
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
@@ -565,7 +565,7 @@ pub fn encode_ty<'tcx>(
             // as vendor extended type.
             let mut s = String::new();
             let name = encode_ty_name(tcx, *def_id);
-            let _ = write!(s, "u{}{}", name.len(), &name);
+            let _ = write!(s, "u{}{}", name.len(), name);
             // Encode parent args only
             s.push_str(&encode_args(
                 tcx,
@@ -588,7 +588,7 @@ pub fn encode_ty<'tcx>(
             s.push('E');
             compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s);
             if ty.is_mutable_ptr() {
-                s = format!("{}{}", "U3mut", &s);
+                s = format!("{}{}", "U3mut", s);
                 compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
             }
             typeid.push_str(&s);
@@ -600,10 +600,10 @@ pub fn encode_ty<'tcx>(
             let mut s = String::new();
             s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
             if !ty.is_mutable_ptr() {
-                s = format!("{}{}", "K", &s);
+                s = format!("{}{}", "K", s);
                 compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
             };
-            s = format!("{}{}", "P", &s);
+            s = format!("{}{}", "P", s);
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
         }
@@ -722,7 +722,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
     s.push('C');
     s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
     let crate_name = tcx.crate_name(def_path.krate).to_string();
-    let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
+    let _ = write!(s, "{}{}", crate_name.len(), crate_name);
 
     // Disambiguators and names
     def_path.data.reverse();
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index fa2acdd4a54..ffc8839435e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1793,25 +1793,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err.children.clear();
 
         let span = obligation.cause.span;
-        if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
+        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
+
+        let mut visitor = ReturnsVisitor::default();
+        visitor.visit_body(&body);
+
+        let (pre, impl_span) = if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
             && snip.starts_with("dyn ")
         {
-            err.span_suggestion(
-                span.with_hi(span.lo() + BytePos(4)),
-                "return an `impl Trait` instead of a `dyn Trait`, \
-                if all returned values are the same type",
+            ("", span.with_hi(span.lo() + BytePos(4)))
+        } else {
+            ("dyn ", span.shrink_to_lo())
+        };
+        let alternatively = if visitor
+            .returns
+            .iter()
+            .map(|expr| self.typeck_results.as_ref().unwrap().expr_ty_adjusted_opt(expr))
+            .collect::<FxHashSet<_>>()
+            .len()
+            <= 1
+        {
+            err.span_suggestion_verbose(
+                impl_span,
+                "consider returning an `impl Trait` instead of a `dyn Trait`",
                 "impl ",
                 Applicability::MaybeIncorrect,
             );
-        }
-
-        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
-
-        let mut visitor = ReturnsVisitor::default();
-        visitor.visit_body(&body);
+            "alternatively, "
+        } else {
+            err.help("if there were a single returned type, you could use `impl Trait` instead");
+            ""
+        };
 
-        let mut sugg =
-            vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
+        let mut sugg = vec![
+            (span.shrink_to_lo(), format!("Box<{pre}")),
+            (span.shrink_to_hi(), ">".to_string()),
+        ];
         sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
             let span =
                 expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
@@ -1837,7 +1854,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }));
 
         err.multipart_suggestion(
-            "box the return type, and wrap all of the returned values in `Box::new`",
+            format!(
+                "{alternatively}box the return type, and wrap all of the returned values in \
+                 `Box::new`",
+            ),
             sugg,
             Applicability::MaybeIncorrect,
         );
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index f1683f5449f..1a51c95ecdf 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -65,15 +65,13 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
 
         match self {
             Param(param) => write!(f, "{param:?}"),
-            Infer(var) => write!(f, "{:?}", &var),
+            Infer(var) => write!(f, "{var:?}"),
             Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
             Placeholder(placeholder) => write!(f, "{placeholder:?}"),
-            Unevaluated(uv) => {
-                write!(f, "{:?}", &uv)
-            }
-            Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &ty),
+            Unevaluated(uv) => write!(f, "{uv:?}"),
+            Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"),
             Error(_) => write!(f, "{{const error}}"),
-            Expr(expr) => write!(f, "{:?}", &expr),
+            Expr(expr) => write!(f, "{expr:?}"),
         }
     }
 }
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index 7abcc370c88..140c89af147 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -232,7 +232,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
 
             ReStatic => f.write_str("'static"),
 
-            ReVar(vid) => write!(f, "{:?}", &vid),
+            ReVar(vid) => write!(f, "{vid:?}"),
 
             RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 4ffebef9f1f..9896425a341 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -367,18 +367,16 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
             }
             Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
             Str => write!(f, "str"),
-            Array(t, c) => write!(f, "[{:?}; {:?}]", &t, &c),
-            Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &t, &p),
+            Array(t, c) => write!(f, "[{t:?}; {c:?}]"),
+            Pat(t, p) => write!(f, "pattern_type!({t:?} is {p:?})"),
             Slice(t) => write!(f, "[{:?}]", &t),
             RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty),
             Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
             FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
-            FnPtr(s) => write!(f, "{:?}", &s),
+            FnPtr(s) => write!(f, "{s:?}"),
             Dynamic(p, r, repr) => match repr {
-                DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &p, &r),
-                DynKind::DynStar => {
-                    write!(f, "dyn* {:?} + {:?}", &p, &r)
-                }
+                DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
+                DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"),
             },
             Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
             CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
@@ -392,7 +390,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
                     if count > 0 {
                         write!(f, ", ")?;
                     }
-                    write!(f, "{:?}", &ty)?;
+                    write!(f, "{ty:?}")?;
                     count += 1;
                 }
                 // unary tuples need a trailing comma
@@ -1050,7 +1048,7 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
             if i > 0 {
                 write!(f, ", ")?;
             }
-            write!(f, "{:?}", &ty)?;
+            write!(f, "{ty:?}")?;
         }
         if *c_variadic {
             if inputs.is_empty() {
diff --git a/compiler/stable_mir/src/mir/pretty.rs b/compiler/stable_mir/src/mir/pretty.rs
index 83734a0d138..18ecccb4536 100644
--- a/compiler/stable_mir/src/mir/pretty.rs
+++ b/compiler/stable_mir/src/mir/pretty.rs
@@ -179,7 +179,7 @@ fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind)
             if !expected {
                 write!(writer, "!")?;
             }
-            write!(writer, "{}, ", &pretty_operand(cond))?;
+            write!(writer, "{}, ", pretty_operand(cond))?;
             pretty_assert_message(writer, msg)?;
             write!(writer, ")")
         }
@@ -325,7 +325,7 @@ fn pretty_ty_const(ct: &TyConst) -> String {
 fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
     match rval {
         Rvalue::AddressOf(mutability, place) => {
-            write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place)
+            write!(writer, "&raw {}(*{:?})", pretty_mut(*mutability), place)
         }
         Rvalue::Aggregate(aggregate_kind, operands) => {
             // FIXME: Add pretty_aggregate function that returns a pretty string
@@ -336,13 +336,13 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
             write!(writer, ")")
         }
         Rvalue::BinaryOp(bin, op1, op2) => {
-            write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
+            write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::Cast(_, op, ty) => {
             write!(writer, "{} as {}", pretty_operand(op), ty)
         }
         Rvalue::CheckedBinaryOp(bin, op1, op2) => {
-            write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
+            write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
         }
         Rvalue::CopyForDeref(deref) => {
             write!(writer, "CopyForDeref({:?})", deref)
@@ -363,7 +363,7 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
             write!(writer, "{kind}{:?}", place)
         }
         Rvalue::Repeat(op, cnst) => {
-            write!(writer, "{} \" \" {}", &pretty_operand(op), &pretty_ty_const(cnst))
+            write!(writer, "{} \" \" {}", pretty_operand(op), pretty_ty_const(cnst))
         }
         Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::ThreadLocalRef(item) => {
diff --git a/config.example.toml b/config.example.toml
index a2c2fa1c2bd..26687bcfb37 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -333,6 +333,7 @@
 #    "rust-analyzer-proc-macro-srv",
 #    "analysis",
 #    "src",
+#    "wasm-component-ld",
 #]
 
 # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index b991b1cf22d..3db2f113860 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -56,7 +56,7 @@ hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true
 wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
 
 [target.'cfg(target_os = "uefi")'.dependencies]
-r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] }
+r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
 r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }
 
 [features]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index f0a73a308a4..eb30a3355e5 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -293,6 +293,7 @@
 #![feature(doc_masked)]
 #![feature(doc_notable_trait)]
 #![feature(dropck_eyepatch)]
+#![feature(extended_varargs_abi_support)]
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs
index 23aa4da14a7..29984a915b8 100644
--- a/library/std/src/sys/pal/uefi/helpers.rs
+++ b/library/std/src/sys/pal/uefi/helpers.rs
@@ -12,15 +12,21 @@
 use r_efi::efi::{self, Guid};
 use r_efi::protocols::{device_path, device_path_to_text};
 
-use crate::ffi::OsString;
+use crate::ffi::{OsStr, OsString};
 use crate::io::{self, const_io_error};
 use crate::mem::{size_of, MaybeUninit};
-use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
+use crate::os::uefi::{self, env::boot_services, ffi::OsStrExt, ffi::OsStringExt};
 use crate::ptr::NonNull;
 use crate::slice;
 use crate::sync::atomic::{AtomicPtr, Ordering};
 use crate::sys_common::wstr::WStrUnits;
 
+type BootInstallMultipleProtocolInterfaces =
+    unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
+
+type BootUninstallMultipleProtocolInterfaces =
+    unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
+
 const BOOT_SERVICES_UNAVAILABLE: io::Error =
     const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
 
@@ -221,3 +227,192 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
     let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services };
     NonNull::new(runtime_services)
 }
+
+pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
+
+impl DevicePath {
+    pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
+        fn inner(
+            p: &OsStr,
+            protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
+        ) -> io::Result<DevicePath> {
+            let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
+            if path_vec[..path_vec.len() - 1].contains(&0) {
+                return Err(const_io_error!(
+                    io::ErrorKind::InvalidInput,
+                    "strings passed to UEFI cannot contain NULs",
+                ));
+            }
+
+            let path =
+                unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
+
+            NonNull::new(path).map(DevicePath).ok_or_else(|| {
+                const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")
+            })
+        }
+
+        static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
+            AtomicPtr::new(crate::ptr::null_mut());
+
+        if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
+            if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
+                handle,
+                r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
+            ) {
+                return inner(p, protocol);
+            }
+        }
+
+        let handles = locate_handles(r_efi::protocols::device_path_from_text::PROTOCOL_GUID)?;
+        for handle in handles {
+            if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
+                handle,
+                r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
+            ) {
+                LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
+                return inner(p, protocol);
+            }
+        }
+
+        io::Result::Err(const_io_error!(
+            io::ErrorKind::NotFound,
+            "DevicePathFromText Protocol not found"
+        ))
+    }
+
+    pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
+        self.0.as_ptr()
+    }
+}
+
+impl Drop for DevicePath {
+    fn drop(&mut self) {
+        if let Some(bt) = boot_services() {
+            let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
+            unsafe {
+                ((*bt.as_ptr()).free_pool)(self.0.as_ptr() as *mut crate::ffi::c_void);
+            }
+        }
+    }
+}
+
+pub(crate) struct OwnedProtocol<T> {
+    guid: r_efi::efi::Guid,
+    handle: NonNull<crate::ffi::c_void>,
+    protocol: *mut T,
+}
+
+impl<T> OwnedProtocol<T> {
+    // FIXME: Consider using unsafe trait for matching protocol with guid
+    pub(crate) unsafe fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result<Self> {
+        let bt: NonNull<r_efi::efi::BootServices> =
+            boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+        let protocol: *mut T = Box::into_raw(Box::new(protocol));
+        let mut handle: r_efi::efi::Handle = crate::ptr::null_mut();
+
+        // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
+        let func: BootInstallMultipleProtocolInterfaces =
+            unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) };
+
+        let r = unsafe {
+            func(
+                &mut handle,
+                &mut guid as *mut _ as *mut crate::ffi::c_void,
+                protocol as *mut crate::ffi::c_void,
+                crate::ptr::null_mut() as *mut crate::ffi::c_void,
+            )
+        };
+
+        if r.is_error() {
+            drop(unsafe { Box::from_raw(protocol) });
+            return Err(crate::io::Error::from_raw_os_error(r.as_usize()));
+        };
+
+        let handle = NonNull::new(handle)
+            .ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?;
+
+        Ok(Self { guid, handle, protocol })
+    }
+
+    pub(crate) fn handle(&self) -> NonNull<crate::ffi::c_void> {
+        self.handle
+    }
+}
+
+impl<T> Drop for OwnedProtocol<T> {
+    fn drop(&mut self) {
+        // Do not deallocate a runtime protocol
+        if let Some(bt) = boot_services() {
+            let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
+            // FIXME: Move into r-efi once extended_varargs_abi_support is stablized
+            let func: BootUninstallMultipleProtocolInterfaces = unsafe {
+                crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces)
+            };
+            let status = unsafe {
+                func(
+                    self.handle.as_ptr(),
+                    &mut self.guid as *mut _ as *mut crate::ffi::c_void,
+                    self.protocol as *mut crate::ffi::c_void,
+                    crate::ptr::null_mut() as *mut crate::ffi::c_void,
+                )
+            };
+
+            // Leak the protocol in case uninstall fails
+            if status == r_efi::efi::Status::SUCCESS {
+                let _ = unsafe { Box::from_raw(self.protocol) };
+            }
+        }
+    }
+}
+
+impl<T> AsRef<T> for OwnedProtocol<T> {
+    fn as_ref(&self) -> &T {
+        unsafe { self.protocol.as_ref().unwrap() }
+    }
+}
+
+pub(crate) struct OwnedTable<T> {
+    layout: crate::alloc::Layout,
+    ptr: *mut T,
+}
+
+impl<T> OwnedTable<T> {
+    pub(crate) fn from_table_header(hdr: &r_efi::efi::TableHeader) -> Self {
+        let header_size = hdr.header_size as usize;
+        let layout = crate::alloc::Layout::from_size_align(header_size, 8).unwrap();
+        let ptr = unsafe { crate::alloc::alloc(layout) as *mut T };
+        Self { layout, ptr }
+    }
+
+    pub(crate) const fn as_ptr(&self) -> *const T {
+        self.ptr
+    }
+
+    pub(crate) const fn as_mut_ptr(&self) -> *mut T {
+        self.ptr
+    }
+}
+
+impl OwnedTable<r_efi::efi::SystemTable> {
+    pub(crate) fn from_table(tbl: *const r_efi::efi::SystemTable) -> Self {
+        let hdr = unsafe { (*tbl).hdr };
+
+        let owned_tbl = Self::from_table_header(&hdr);
+        unsafe {
+            crate::ptr::copy_nonoverlapping(
+                tbl as *const u8,
+                owned_tbl.as_mut_ptr() as *mut u8,
+                hdr.header_size as usize,
+            )
+        };
+
+        owned_tbl
+    }
+}
+
+impl<T> Drop for OwnedTable<T> {
+    fn drop(&mut self) {
+        unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) };
+    }
+}
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 4d50d9e8c3d..c54e9477bfc 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -25,7 +25,6 @@ pub mod net;
 pub mod os;
 #[path = "../unsupported/pipe.rs"]
 pub mod pipe;
-#[path = "../unsupported/process.rs"]
 pub mod process;
 pub mod stdio;
 pub mod thread;
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
new file mode 100644
index 00000000000..5c7c8415ee2
--- /dev/null
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -0,0 +1,689 @@
+use r_efi::protocols::simple_text_output;
+
+use crate::ffi::OsStr;
+use crate::ffi::OsString;
+use crate::fmt;
+use crate::io;
+use crate::num::NonZero;
+use crate::num::NonZeroI32;
+use crate::path::Path;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::unsupported;
+use crate::sys_common::process::{CommandEnv, CommandEnvs};
+
+pub use crate::ffi::OsString as EnvKey;
+
+use super::helpers;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+#[derive(Debug)]
+pub struct Command {
+    prog: OsString,
+    stdout: Option<Stdio>,
+    stderr: Option<Stdio>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(program: &OsStr) -> Command {
+        Command { prog: program.to_os_string(), stdout: None, stderr: None }
+    }
+
+    // FIXME: Implement arguments as reverse of parsing algorithm
+    pub fn arg(&mut self, _arg: &OsStr) {
+        panic!("unsupported")
+    }
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
+        panic!("unsupported")
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {
+        panic!("unsupported")
+    }
+
+    pub fn stdin(&mut self, _stdin: Stdio) {
+        panic!("unsupported")
+    }
+
+    pub fn stdout(&mut self, stdout: Stdio) {
+        self.stdout = Some(stdout);
+    }
+
+    pub fn stderr(&mut self, stderr: Stdio) {
+        self.stderr = Some(stderr);
+    }
+
+    pub fn get_program(&self) -> &OsStr {
+        self.prog.as_ref()
+    }
+
+    pub fn get_args(&self) -> CommandArgs<'_> {
+        panic!("unsupported")
+    }
+
+    pub fn get_envs(&self) -> CommandEnvs<'_> {
+        panic!("unsupported")
+    }
+
+    pub fn get_current_dir(&self) -> Option<&Path> {
+        None
+    }
+
+    pub fn spawn(
+        &mut self,
+        _default: Stdio,
+        _needs_stdin: bool,
+    ) -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+
+    fn create_pipe(
+        s: Stdio,
+    ) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::PipeProtocol>>> {
+        match s {
+            Stdio::MakePipe => unsafe {
+                helpers::OwnedProtocol::create(
+                    uefi_command_internal::PipeProtocol::new(),
+                    simple_text_output::PROTOCOL_GUID,
+                )
+            }
+            .map(Some),
+            Stdio::Null => unsafe {
+                helpers::OwnedProtocol::create(
+                    uefi_command_internal::PipeProtocol::null(),
+                    simple_text_output::PROTOCOL_GUID,
+                )
+            }
+            .map(Some),
+            Stdio::Inherit => Ok(None),
+        }
+    }
+
+    pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
+        let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
+
+        // Setup Stdout
+        let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
+        let stdout = Self::create_pipe(stdout)?;
+        if let Some(con) = stdout {
+            cmd.stdout_init(con)
+        } else {
+            cmd.stdout_inherit()
+        };
+
+        // Setup Stderr
+        let stderr = self.stderr.unwrap_or(Stdio::MakePipe);
+        let stderr = Self::create_pipe(stderr)?;
+        if let Some(con) = stderr {
+            cmd.stderr_init(con)
+        } else {
+            cmd.stderr_inherit()
+        };
+
+        let stat = cmd.start_image()?;
+
+        let stdout = cmd.stdout()?;
+        let stderr = cmd.stderr()?;
+
+        Ok((ExitStatus(stat), stdout, stderr))
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+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")
+    }
+}
+
+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")
+    }
+}
+
+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")
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[non_exhaustive]
+pub struct ExitStatus(r_efi::efi::Status);
+
+impl ExitStatus {
+    pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
+        if self.0 == r_efi::efi::Status::SUCCESS { Ok(()) } else { Err(ExitStatusError(self.0)) }
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        Some(self.0.as_usize() as i32)
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let err_str = super::os::error_string(self.0.as_usize());
+        write!(f, "{}", err_str)
+    }
+}
+
+impl Default for ExitStatus {
+    fn default() -> Self {
+        ExitStatus(r_efi::efi::Status::SUCCESS)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub struct ExitStatusError(r_efi::efi::Status);
+
+impl fmt::Debug for ExitStatusError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let err_str = super::os::error_string(self.0.as_usize());
+        write!(f, "{}", err_str)
+    }
+}
+
+impl Into<ExitStatus> for ExitStatusError {
+    fn into(self) -> ExitStatus {
+        ExitStatus(self.0)
+    }
+}
+
+impl ExitStatusError {
+    pub fn code(self) -> Option<NonZero<i32>> {
+        NonZeroI32::new(self.0.as_usize() as i32)
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        match code {
+            0 => Self::SUCCESS,
+            1..=255 => Self::FAILURE,
+        }
+    }
+}
+
+pub struct Process(!);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        self.0
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        self.0
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        self.0
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        self.0
+    }
+}
+
+pub struct CommandArgs<'a> {
+    iter: crate::slice::Iter<'a, OsString>,
+}
+
+impl<'a> Iterator for CommandArgs<'a> {
+    type Item = &'a OsStr;
+
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.iter.next().map(|x| x.as_ref())
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+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().entries(self.iter.clone()).finish()
+    }
+}
+
+#[allow(dead_code)]
+mod uefi_command_internal {
+    use r_efi::protocols::{loaded_image, simple_text_output};
+
+    use super::super::helpers;
+    use crate::ffi::{OsStr, OsString};
+    use crate::io::{self, const_io_error};
+    use crate::mem::MaybeUninit;
+    use crate::os::uefi::env::{boot_services, image_handle, system_table};
+    use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
+    use crate::ptr::NonNull;
+    use crate::slice;
+    use crate::sys::pal::uefi::helpers::OwnedTable;
+    use crate::sys_common::wstr::WStrUnits;
+
+    pub struct Image {
+        handle: NonNull<crate::ffi::c_void>,
+        stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
+        stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
+        st: OwnedTable<r_efi::efi::SystemTable>,
+        args: Option<Vec<u16>>,
+    }
+
+    impl Image {
+        pub fn load_image(p: &OsStr) -> io::Result<Self> {
+            let path = helpers::DevicePath::from_text(p)?;
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
+                .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
+                .cast();
+            let mut child_handle: MaybeUninit<r_efi::efi::Handle> = MaybeUninit::uninit();
+            let image_handle = image_handle();
+
+            let r = unsafe {
+                ((*boot_services.as_ptr()).load_image)(
+                    r_efi::efi::Boolean::FALSE,
+                    image_handle.as_ptr(),
+                    path.as_ptr(),
+                    crate::ptr::null_mut(),
+                    0,
+                    child_handle.as_mut_ptr(),
+                )
+            };
+
+            if r.is_error() {
+                Err(io::Error::from_raw_os_error(r.as_usize()))
+            } else {
+                let child_handle = unsafe { child_handle.assume_init() };
+                let child_handle = NonNull::new(child_handle).unwrap();
+
+                let loaded_image: NonNull<loaded_image::Protocol> =
+                    helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
+                let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
+
+                Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
+            }
+        }
+
+        pub fn start_image(&mut self) -> io::Result<r_efi::efi::Status> {
+            self.update_st_crc32()?;
+
+            // Use our system table instead of the default one
+            let loaded_image: NonNull<loaded_image::Protocol> =
+                helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
+            unsafe {
+                (*loaded_image.as_ptr()).system_table = self.st.as_mut_ptr();
+            }
+
+            let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
+                .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
+                .cast();
+            let mut exit_data_size: usize = 0;
+            let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit();
+
+            let r = unsafe {
+                ((*boot_services.as_ptr()).start_image)(
+                    self.handle.as_ptr(),
+                    &mut exit_data_size,
+                    exit_data.as_mut_ptr(),
+                )
+            };
+
+            // Drop exitdata
+            if exit_data_size != 0 {
+                unsafe {
+                    let exit_data = exit_data.assume_init();
+                    ((*boot_services.as_ptr()).free_pool)(exit_data as *mut crate::ffi::c_void);
+                }
+            }
+
+            Ok(r)
+        }
+
+        fn set_stdout(
+            &mut self,
+            handle: r_efi::efi::Handle,
+            protocol: *mut simple_text_output::Protocol,
+        ) {
+            unsafe {
+                (*self.st.as_mut_ptr()).console_out_handle = handle;
+                (*self.st.as_mut_ptr()).con_out = protocol;
+            }
+        }
+
+        fn set_stderr(
+            &mut self,
+            handle: r_efi::efi::Handle,
+            protocol: *mut simple_text_output::Protocol,
+        ) {
+            unsafe {
+                (*self.st.as_mut_ptr()).standard_error_handle = handle;
+                (*self.st.as_mut_ptr()).std_err = protocol;
+            }
+        }
+
+        pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
+            self.set_stdout(
+                protocol.handle().as_ptr(),
+                protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
+            );
+            self.stdout = Some(protocol);
+        }
+
+        pub fn stdout_inherit(&mut self) {
+            let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
+            unsafe { self.set_stdout((*st.as_ptr()).console_out_handle, (*st.as_ptr()).con_out) }
+        }
+
+        pub fn stderr_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
+            self.set_stderr(
+                protocol.handle().as_ptr(),
+                protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
+            );
+            self.stderr = Some(protocol);
+        }
+
+        pub fn stderr_inherit(&mut self) {
+            let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
+            unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
+        }
+
+        pub fn stderr(&self) -> io::Result<Vec<u8>> {
+            match &self.stderr {
+                Some(stderr) => stderr.as_ref().utf8(),
+                None => Ok(Vec::new()),
+            }
+        }
+
+        pub fn stdout(&self) -> io::Result<Vec<u8>> {
+            match &self.stdout {
+                Some(stdout) => stdout.as_ref().utf8(),
+                None => Ok(Vec::new()),
+            }
+        }
+
+        pub fn set_args(&mut self, args: &OsStr) {
+            let loaded_image: NonNull<loaded_image::Protocol> =
+                helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
+
+            let mut args = args.encode_wide().collect::<Vec<u16>>();
+            let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
+
+            unsafe {
+                (*loaded_image.as_ptr()).load_options =
+                    args.as_mut_ptr() as *mut crate::ffi::c_void;
+                (*loaded_image.as_ptr()).load_options_size = args_size;
+            }
+
+            self.args = Some(args);
+        }
+
+        fn update_st_crc32(&mut self) -> io::Result<()> {
+            let bt: NonNull<r_efi::efi::BootServices> = boot_services().unwrap().cast();
+            let st_size = unsafe { (*self.st.as_ptr()).hdr.header_size as usize };
+            let mut crc32: u32 = 0;
+
+            // Set crc to 0 before calcuation
+            unsafe {
+                (*self.st.as_mut_ptr()).hdr.crc32 = 0;
+            }
+
+            let r = unsafe {
+                ((*bt.as_ptr()).calculate_crc32)(
+                    self.st.as_mut_ptr() as *mut crate::ffi::c_void,
+                    st_size,
+                    &mut crc32,
+                )
+            };
+
+            if r.is_error() {
+                Err(io::Error::from_raw_os_error(r.as_usize()))
+            } else {
+                unsafe {
+                    (*self.st.as_mut_ptr()).hdr.crc32 = crc32;
+                }
+                Ok(())
+            }
+        }
+    }
+
+    impl Drop for Image {
+        fn drop(&mut self) {
+            if let Some(bt) = boot_services() {
+                let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
+                unsafe {
+                    ((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
+                }
+            }
+        }
+    }
+
+    #[repr(C)]
+    pub struct PipeProtocol {
+        reset: simple_text_output::ProtocolReset,
+        output_string: simple_text_output::ProtocolOutputString,
+        test_string: simple_text_output::ProtocolTestString,
+        query_mode: simple_text_output::ProtocolQueryMode,
+        set_mode: simple_text_output::ProtocolSetMode,
+        set_attribute: simple_text_output::ProtocolSetAttribute,
+        clear_screen: simple_text_output::ProtocolClearScreen,
+        set_cursor_position: simple_text_output::ProtocolSetCursorPosition,
+        enable_cursor: simple_text_output::ProtocolEnableCursor,
+        mode: *mut simple_text_output::Mode,
+        _buffer: Vec<u16>,
+    }
+
+    impl PipeProtocol {
+        pub fn new() -> Self {
+            let mode = Box::new(simple_text_output::Mode {
+                max_mode: 0,
+                mode: 0,
+                attribute: 0,
+                cursor_column: 0,
+                cursor_row: 0,
+                cursor_visible: r_efi::efi::Boolean::FALSE,
+            });
+            Self {
+                reset: Self::reset,
+                output_string: Self::output_string,
+                test_string: Self::test_string,
+                query_mode: Self::query_mode,
+                set_mode: Self::set_mode,
+                set_attribute: Self::set_attribute,
+                clear_screen: Self::clear_screen,
+                set_cursor_position: Self::set_cursor_position,
+                enable_cursor: Self::enable_cursor,
+                mode: Box::into_raw(mode),
+                _buffer: Vec::new(),
+            }
+        }
+
+        pub fn null() -> Self {
+            let mode = Box::new(simple_text_output::Mode {
+                max_mode: 0,
+                mode: 0,
+                attribute: 0,
+                cursor_column: 0,
+                cursor_row: 0,
+                cursor_visible: r_efi::efi::Boolean::FALSE,
+            });
+            Self {
+                reset: Self::reset_null,
+                output_string: Self::output_string_null,
+                test_string: Self::test_string,
+                query_mode: Self::query_mode,
+                set_mode: Self::set_mode,
+                set_attribute: Self::set_attribute,
+                clear_screen: Self::clear_screen,
+                set_cursor_position: Self::set_cursor_position,
+                enable_cursor: Self::enable_cursor,
+                mode: Box::into_raw(mode),
+                _buffer: Vec::new(),
+            }
+        }
+
+        pub fn utf8(&self) -> io::Result<Vec<u8>> {
+            OsString::from_wide(&self._buffer)
+                .into_string()
+                .map(Into::into)
+                .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed"))
+        }
+
+        extern "efiapi" fn reset(
+            proto: *mut simple_text_output::Protocol,
+            _: r_efi::efi::Boolean,
+        ) -> r_efi::efi::Status {
+            let proto: *mut PipeProtocol = proto.cast();
+            unsafe {
+                (*proto)._buffer.clear();
+            }
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn reset_null(
+            _: *mut simple_text_output::Protocol,
+            _: r_efi::efi::Boolean,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn output_string(
+            proto: *mut simple_text_output::Protocol,
+            buf: *mut r_efi::efi::Char16,
+        ) -> r_efi::efi::Status {
+            let proto: *mut PipeProtocol = proto.cast();
+            let buf_len = unsafe {
+                if let Some(x) = WStrUnits::new(buf) {
+                    x.count()
+                } else {
+                    return r_efi::efi::Status::INVALID_PARAMETER;
+                }
+            };
+            let buf_slice = unsafe { slice::from_raw_parts(buf, buf_len) };
+
+            unsafe {
+                (*proto)._buffer.extend_from_slice(buf_slice);
+            };
+
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn output_string_null(
+            _: *mut simple_text_output::Protocol,
+            _: *mut r_efi::efi::Char16,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn test_string(
+            _: *mut simple_text_output::Protocol,
+            _: *mut r_efi::efi::Char16,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::SUCCESS
+        }
+
+        extern "efiapi" fn query_mode(
+            _: *mut simple_text_output::Protocol,
+            _: usize,
+            _: *mut usize,
+            _: *mut usize,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn set_mode(
+            _: *mut simple_text_output::Protocol,
+            _: usize,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn set_attribute(
+            _: *mut simple_text_output::Protocol,
+            _: usize,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn clear_screen(
+            _: *mut simple_text_output::Protocol,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn set_cursor_position(
+            _: *mut simple_text_output::Protocol,
+            _: usize,
+            _: usize,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+
+        extern "efiapi" fn enable_cursor(
+            _: *mut simple_text_output::Protocol,
+            _: r_efi::efi::Boolean,
+        ) -> r_efi::efi::Status {
+            r_efi::efi::Status::UNSUPPORTED
+        }
+    }
+
+    impl Drop for PipeProtocol {
+        fn drop(&mut self) {
+            unsafe {
+                let _ = Box::from_raw(self.mode);
+            }
+        }
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 7b98f2ae763..e9731bc85d6 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -161,7 +161,7 @@ mod tests;
 use crate::any::Any;
 use crate::cell::{Cell, OnceCell, UnsafeCell};
 use crate::env;
-use crate::ffi::{CStr, CString};
+use crate::ffi::CStr;
 use crate::fmt;
 use crate::io;
 use crate::marker::PhantomData;
@@ -487,11 +487,7 @@ impl Builder {
             amt
         });
 
-        let my_thread = name.map_or_else(Thread::new_unnamed, |name| unsafe {
-            Thread::new(
-                CString::new(name).expect("thread name may not contain interior null bytes"),
-            )
-        });
+        let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new);
         let their_thread = my_thread.clone();
 
         let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
@@ -1299,10 +1295,51 @@ impl ThreadId {
 /// The internal representation of a `Thread`'s name.
 enum ThreadName {
     Main,
-    Other(CString),
+    Other(ThreadNameString),
     Unnamed,
 }
 
+// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
+mod thread_name_string {
+    use super::ThreadName;
+    use crate::ffi::{CStr, CString};
+    use core::str;
+
+    /// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
+    pub(crate) struct ThreadNameString {
+        inner: CString,
+    }
+    impl core::ops::Deref for ThreadNameString {
+        type Target = CStr;
+        fn deref(&self) -> &CStr {
+            &self.inner
+        }
+    }
+    impl From<String> for ThreadNameString {
+        fn from(s: String) -> Self {
+            Self {
+                inner: CString::new(s).expect("thread name may not contain interior null bytes"),
+            }
+        }
+    }
+    impl ThreadName {
+        pub fn as_cstr(&self) -> Option<&CStr> {
+            match self {
+                ThreadName::Main => Some(c"main"),
+                ThreadName::Other(other) => Some(other),
+                ThreadName::Unnamed => None,
+            }
+        }
+
+        pub fn as_str(&self) -> Option<&str> {
+            // SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
+            // which is guaranteed to be UTF-8.
+            self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
+        }
+    }
+}
+pub(crate) use thread_name_string::ThreadNameString;
+
 /// The internal representation of a `Thread` handle
 struct Inner {
     name: ThreadName, // Guaranteed to be UTF-8
@@ -1342,25 +1379,20 @@ pub struct Thread {
 
 impl Thread {
     /// Used only internally to construct a thread object without spawning.
-    ///
-    /// # Safety
-    /// `name` must be valid UTF-8.
-    pub(crate) unsafe fn new(name: CString) -> Thread {
-        unsafe { Self::new_inner(ThreadName::Other(name)) }
+    pub(crate) fn new(name: String) -> Thread {
+        Self::new_inner(ThreadName::Other(name.into()))
     }
 
     pub(crate) fn new_unnamed() -> Thread {
-        unsafe { Self::new_inner(ThreadName::Unnamed) }
+        Self::new_inner(ThreadName::Unnamed)
     }
 
     // Used in runtime to construct main thread
     pub(crate) fn new_main() -> Thread {
-        unsafe { Self::new_inner(ThreadName::Main) }
+        Self::new_inner(ThreadName::Main)
     }
 
-    /// # Safety
-    /// If `name` is `ThreadName::Other(_)`, the contained string must be valid UTF-8.
-    unsafe fn new_inner(name: ThreadName) -> Thread {
+    fn new_inner(name: ThreadName) -> Thread {
         // We have to use `unsafe` here to construct the `Parker` in-place,
         // which is required for the UNIX implementation.
         //
@@ -1483,15 +1515,11 @@ impl Thread {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
     pub fn name(&self) -> Option<&str> {
-        self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
+        self.inner.name.as_str()
     }
 
     fn cname(&self) -> Option<&CStr> {
-        match &self.inner.name {
-            ThreadName::Main => Some(c"main"),
-            ThreadName::Other(other) => Some(&other),
-            ThreadName::Unnamed => None,
-        }
+        self.inner.name.as_cstr()
     }
 }
 
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index d4dd3e546ec..3e79acad1c4 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -695,7 +695,7 @@ fn copy_sanitizers(
             || target == "x86_64-apple-ios"
         {
             // Update the library’s install name to reflect that it has been renamed.
-            apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name));
+            apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", runtime.name));
             // Upon renaming the install name, the code signature of the file will invalidate,
             // so we will sign it again.
             apple_darwin_sign_file(builder, &dst);
@@ -1820,12 +1820,14 @@ impl Step for Assemble {
                     &self_contained_lld_dir.join(exe(name, target_compiler.host)),
                 );
             }
+        }
 
-            // In addition to `rust-lld` also install `wasm-component-ld` when
-            // LLD is enabled. This is a relatively small binary that primarily
-            // delegates to the `rust-lld` binary for linking and then runs
-            // logic to create the final binary. This is used by the
-            // `wasm32-wasip2` target of Rust.
+        // In addition to `rust-lld` also install `wasm-component-ld` when
+        // LLD is enabled. This is a relatively small binary that primarily
+        // delegates to the `rust-lld` binary for linking and then runs
+        // logic to create the final binary. This is used by the
+        // `wasm32-wasip2` target of Rust.
+        if builder.build_wasm_component_ld() {
             let wasm_component_ld_exe =
                 builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
                     compiler: build_compiler,
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 888290a0479..44790301841 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -1411,7 +1411,7 @@ impl Step for Libunwind {
                 }
             }
         }
-        assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
+        assert_eq!(cpp_len, count, "Can't get object files from {out_dir:?}");
 
         cc_cfg.compile("unwind");
         out_dir
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index a77c20067e6..d2910f8edc6 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -1414,6 +1414,19 @@ Executed at: {executed_at}"#,
         None
     }
 
+    /// Returns whether it's requested that `wasm-component-ld` is built as part
+    /// of the sysroot. This is done either with the `extended` key in
+    /// `config.toml` or with the `tools` set.
+    fn build_wasm_component_ld(&self) -> bool {
+        if self.config.extended {
+            return true;
+        }
+        match &self.config.tools {
+            Some(set) => set.contains("wasm-component-ld"),
+            None => false,
+        }
+    }
+
     /// Returns the root of the "rootfs" image that this target will be using,
     /// if one was configured.
     ///
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index d6fa7fc0bbe..20d79e490ec 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -142,15 +142,15 @@ pub fn find_target(build: &Build, target: TargetSelection) {
         build.cxx.borrow_mut().insert(target, compiler);
     }
 
-    build.verbose(|| println!("CC_{} = {:?}", &target.triple, build.cc(target)));
-    build.verbose(|| println!("CFLAGS_{} = {:?}", &target.triple, cflags));
+    build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
+    build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
     if let Ok(cxx) = build.cxx(target) {
         let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
-        build.verbose(|| println!("CXX_{} = {:?}", &target.triple, cxx));
-        build.verbose(|| println!("CXXFLAGS_{} = {:?}", &target.triple, cxxflags));
+        build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
+        build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
     }
     if let Some(ar) = ar {
-        build.verbose(|| println!("AR_{} = {:?}", &target.triple, ar));
+        build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
         build.ar.borrow_mut().insert(target, ar);
     }
 
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 6a7c5c0f9b7..083418ed066 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -205,4 +205,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "`debug-logging` option has been removed from the default `tools` profile.",
     },
+    ChangeInfo {
+        change_id: 127866,
+        severity: ChangeSeverity::Info,
+        summary: "the `wasm-component-ld` tool is now built as part of `build.extended` and can be a member of `build.tools`",
+    },
 ];
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 9378c35127f..28a295e3e2a 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -244,7 +244,7 @@ impl<'a> Tarball<'a> {
             cmd.arg("generate")
                 .arg("--image-dir")
                 .arg(&this.image_dir)
-                .arg(format!("--component-name={}", &component_name));
+                .arg(format!("--component-name={component_name}"));
 
             if let Some((dir, dirs)) = this.bulk_dirs.split_first() {
                 let mut arg = dir.as_os_str().to_os_string();
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 9b0b2571ec1..055781f7fed 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -850,7 +850,7 @@ fn resolved_path<'cx>(
         }
     }
     if w.alternate() {
-        write!(w, "{}{:#}", &last.name, last.args.print(cx))?;
+        write!(w, "{}{:#}", last.name, last.args.print(cx))?;
     } else {
         let path = if use_absolute {
             if let Ok((_, _, fqp)) = href(did, cx) {
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index bd25a6c144e..4b50bcb38fd 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -9,7 +9,6 @@ run-make/cat-and-grep-sanity-check/Makefile
 run-make/cdylib-dylib-linkage/Makefile
 run-make/compiler-lookup-paths-2/Makefile
 run-make/compiler-rt-works-on-mingw/Makefile
-run-make/crate-hash-rustc-version/Makefile
 run-make/cross-lang-lto-clang/Makefile
 run-make/cross-lang-lto-pgo-smoketest/Makefile
 run-make/cross-lang-lto-upstream-rlibs/Makefile
diff --git a/tests/run-make/crate-hash-rustc-version/Makefile b/tests/run-make/crate-hash-rustc-version/Makefile
deleted file mode 100644
index 6bf504bf01b..00000000000
--- a/tests/run-make/crate-hash-rustc-version/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Ensure that crates compiled with different rustc versions cannot
-# be dynamically linked.
-
-FLAGS := -Cprefer-dynamic -Csymbol-mangling-version=v0
-UNAME := $(shell uname)
-ifeq ($(UNAME),Linux)
-  EXT=".so"
-  NM_CMD := nm -D
-endif
-ifeq ($(UNAME),Darwin)
-  EXT=".dylib"
-  NM_CMD := nm
-endif
-
-ifndef NM_CMD
-all:
-	exit 0
-else
-all:
-	# a.rs is a dylib
-	$(RUSTC) a.rs --crate-type=dylib $(FLAGS)
-	# Write symbols to disk.
-	$(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsbefore
-	# b.rs is a binary
-	$(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS)
-	$(call RUN,b)
-	# Now re-compile a.rs with another rustc version
-	RUSTC_FORCE_RUSTC_VERSION=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
-	# After compiling with a different rustc version, write symbols to disk again.
-	$(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter
-	# As a sanity check, test if the symbols changed:
-	# If the symbols are identical, there's been an error.
-	if diff $(TMPDIR)/symbolsbefore $(TMPDIR)/symbolsafter; then exit 1; fi
-	$(call FAIL,b)
-endif
diff --git a/tests/run-make/crate-hash-rustc-version/rmake.rs b/tests/run-make/crate-hash-rustc-version/rmake.rs
new file mode 100644
index 00000000000..97b3dd3931e
--- /dev/null
+++ b/tests/run-make/crate-hash-rustc-version/rmake.rs
@@ -0,0 +1,57 @@
+// Ensure that crates compiled with different rustc versions cannot
+// be dynamically linked.
+
+//@ ignore-cross-compile
+//@ only-unix
+
+use run_make_support::llvm;
+use run_make_support::{diff, dynamic_lib_name, is_darwin, run, run_fail, rustc};
+
+fn llvm_readobj() -> llvm::LlvmReadobj {
+    let mut cmd = llvm::llvm_readobj();
+    if is_darwin() {
+        cmd.symbols();
+    } else {
+        cmd.dynamic_table();
+    }
+    cmd
+}
+
+fn main() {
+    let flags = ["-Cprefer-dynamic", "-Csymbol-mangling-version=v0"];
+
+    // a.rs is compiled to a dylib
+    rustc().input("a.rs").crate_type("dylib").args(&flags).run();
+
+    // Store symbols
+    let symbols_before = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8();
+
+    // b.rs is compiled to a binary
+    rustc()
+        .input("b.rs")
+        .extern_("a", dynamic_lib_name("a"))
+        .crate_type("bin")
+        .arg("-Crpath")
+        .args(&flags)
+        .run();
+    run("b");
+
+    // Now re-compile a.rs with another rustc version
+    rustc()
+        .env("RUSTC_FORCE_RUSTC_VERSION", "deadfeed")
+        .input("a.rs")
+        .crate_type("dylib")
+        .args(&flags)
+        .run();
+
+    // After compiling with a different rustc version, store symbols again.
+    let symbols_after = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8();
+
+    // As a sanity check, test if the symbols changed:
+    // If the symbols are identical, there's been an error.
+    diff()
+        .expected_text("symbols_before", symbols_before)
+        .actual_text("symbols_after", symbols_after)
+        .run_fail();
+    run_fail("b");
+}
diff --git a/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.rs b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.rs
new file mode 100644
index 00000000000..e422026ca4a
--- /dev/null
+++ b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.rs
@@ -0,0 +1,15 @@
+#![allow(dead_code)]
+
+extern "C" {
+    fn rust_interesting_average(_: i64, ...) -> f64;
+}
+
+fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
+    unsafe {
+        rust_interesting_average(
+            6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g, //~ ERROR use of moved value: `f` [E0382]
+        ) as i64
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr
new file mode 100644
index 00000000000..6997710ec89
--- /dev/null
+++ b/tests/ui/borrowck/move-error-suggest-clone-panic-issue-127915.stderr
@@ -0,0 +1,25 @@
+error[E0382]: use of moved value: `f`
+  --> $DIR/move-error-suggest-clone-panic-issue-127915.rs:10:78
+   |
+LL | fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
+   |                                                       - move occurs because `f` has type `T`, which does not implement the `Copy` trait
+...
+LL |             6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g,
+   |                                       - value moved here                     ^ value used here after move
+   |
+help: if `T` implemented `Clone`, you could clone the value
+  --> $DIR/move-error-suggest-clone-panic-issue-127915.rs:7:9
+   |
+LL | fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
+   |         ^ consider constraining this type parameter with `Clone`
+...
+LL |             6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g,
+   |                                       - you could clone this value
+help: consider restricting type parameter `T`
+   |
+LL | fn test<T: Copy, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
+   |          ++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/error-codes/E0746.stderr b/tests/ui/error-codes/E0746.stderr
index 9fe90ab7bec..cfc747cb1e2 100644
--- a/tests/ui/error-codes/E0746.stderr
+++ b/tests/ui/error-codes/E0746.stderr
@@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn foo() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn foo() -> impl Trait { Struct }
    |             ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) }
    |             ++++         +   +++++++++      +
@@ -19,10 +19,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bar() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn bar() -> impl Trait {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn bar() -> Box<dyn Trait> {
diff --git a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
index f25269ca032..9c546659564 100644
--- a/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
+++ b/tests/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr
@@ -48,10 +48,14 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bap() -> Trait { Struct }
    |             ^^^^^ doesn't have a size known at compile-time
    |
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: consider returning an `impl Trait` instead of a `dyn Trait`
+   |
+LL | fn bap() -> impl Trait { Struct }
+   |             ++++
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
-LL | fn bap() -> Box<Trait> { Box::new(Struct) }
-   |             ++++     +   +++++++++      +
+LL | fn bap() -> Box<dyn Trait> { Box::new(Struct) }
+   |             +++++++      +   +++++++++      +
 
 error[E0746]: return type cannot have an unboxed trait object
   --> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
@@ -59,11 +63,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn ban() -> dyn Trait { Struct }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn ban() -> impl Trait { Struct }
    |             ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) }
    |             ++++         +   +++++++++      +
@@ -74,11 +78,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bak() -> dyn Trait { unimplemented!() }
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn bak() -> impl Trait { unimplemented!() }
    |             ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) }
    |             ++++         +   +++++++++                +
@@ -89,10 +93,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bal() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn bal() -> impl Trait {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn bal() -> Box<dyn Trait> {
@@ -108,10 +109,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bax() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn bax() -> impl Trait {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn bax() -> Box<dyn Trait> {
@@ -263,10 +261,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bat() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn bat() -> impl Trait {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn bat() -> Box<dyn Trait> {
@@ -282,10 +277,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn bay() -> dyn Trait {
    |             ^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn bay() -> impl Trait {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn bay() -> Box<dyn Trait> {
diff --git a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
index fc9c30abf13..09a689e6396 100644
--- a/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
+++ b/tests/ui/impl-trait/object-unsafe-trait-in-return-position-dyn-trait.stderr
@@ -54,10 +54,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn car() -> dyn NotObjectSafe {
    |             ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn car() -> impl NotObjectSafe {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn car() -> Box<dyn NotObjectSafe> {
diff --git a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
index 9205d74504f..54849c112f5 100644
--- a/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
+++ b/tests/ui/impl-trait/point-to-type-err-cause-on-impl-trait-return.stderr
@@ -171,11 +171,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn hat() -> dyn std::fmt::Display {
    |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn hat() -> impl std::fmt::Display {
    |             ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn hat() -> Box<dyn std::fmt::Display> {
 LL |     match 13 {
@@ -192,11 +192,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn pug() -> dyn std::fmt::Display {
    |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn pug() -> impl std::fmt::Display {
    |             ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn pug() -> Box<dyn std::fmt::Display> {
 LL |     match 13 {
@@ -211,10 +211,7 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn man() -> dyn std::fmt::Display {
    |             ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
-   |
-LL | fn man() -> impl std::fmt::Display {
-   |             ~~~~
+   = help: if there were a single returned type, you could use `impl Trait` instead
 help: box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn man() -> Box<dyn std::fmt::Display> {
diff --git a/tests/ui/issues/issue-18107.stderr b/tests/ui/issues/issue-18107.stderr
index 702207c30f7..705f7d0df12 100644
--- a/tests/ui/issues/issue-18107.stderr
+++ b/tests/ui/issues/issue-18107.stderr
@@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL |     dyn AbstractRenderer
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL |     impl AbstractRenderer
    |     ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~     Box<dyn AbstractRenderer>
 LL |
diff --git a/tests/ui/unsized/box-instead-of-dyn-fn.stderr b/tests/ui/unsized/box-instead-of-dyn-fn.stderr
index f2828b384b2..1f1845569ef 100644
--- a/tests/ui/unsized/box-instead-of-dyn-fn.stderr
+++ b/tests/ui/unsized/box-instead-of-dyn-fn.stderr
@@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a {
    |                                                        ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
    |                                                        ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL ~ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
 LL |
diff --git a/tests/ui/unsized/issue-91801.stderr b/tests/ui/unsized/issue-91801.stderr
index d1d652d1860..e13cabbb81d 100644
--- a/tests/ui/unsized/issue-91801.stderr
+++ b/tests/ui/unsized/issue-91801.stderr
@@ -4,10 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
    |                                                                             ^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
-LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
-   |                                                                             ++++             +
+LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Validator<'a> {
+   |                                                                             ++++
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
+   |
+LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<dyn Validator<'a>> {
+   |                                                                             +++++++              +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unsized/issue-91803.stderr b/tests/ui/unsized/issue-91803.stderr
index 632af02b4b6..3b89066499d 100644
--- a/tests/ui/unsized/issue-91803.stderr
+++ b/tests/ui/unsized/issue-91803.stderr
@@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
 LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
    |                                           ^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
+help: consider returning an `impl Trait` instead of a `dyn Trait`
    |
 LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> {
    |                                           ~~~~
-help: box the return type, and wrap all of the returned values in `Box::new`
+help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
    |
 LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> {
    |                                           ++++           +