about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-21 06:13:34 +0000
committerbors <bors@rust-lang.org>2024-10-21 06:13:34 +0000
commit93742bd782e7142899d782f663448ab51a3eec9b (patch)
treee1194cab84a77a616063c11b332e70ce5f555348
parentf2ba41113d3f86e6bb8a4f22c2967bba63369754 (diff)
parent62b7293a90452d7d7dcbaa63695e6e1a6cb72a3c (diff)
downloadrust-93742bd782e7142899d782f663448ab51a3eec9b.tar.gz
rust-93742bd782e7142899d782f663448ab51a3eec9b.zip
Auto merge of #131988 - matthiaskrgr:rollup-tx173wn, r=matthiaskrgr
Rollup of 4 pull requests

Successful merges:

 - #126588 (Added more scenarios where comma to be removed in the function arg)
 - #131728 (bootstrap: extract builder cargo to its own module)
 - #131968 (Rip out old effects var handling code from traits)
 - #131981 (Remove the `BoundConstness::NotConst` variant)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_const_eval/src/check_consts/qualifs.rs53
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs21
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs35
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs30
-rw-r--r--compiler/rustc_middle/src/traits/select.rs7
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs12
-rw-r--r--compiler/rustc_middle/src/ty/util.rs18
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs7
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs12
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs27
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs36
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs112
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs191
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs11
-rw-r--r--compiler/rustc_type_ir/src/predicate.rs6
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs1220
-rw-r--r--src/bootstrap/src/core/builder/mod.rs (renamed from src/bootstrap/src/core/builder.rs)1218
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs15
-rw-r--r--tests/ui/argument-suggestions/issue-109425.fixed4
-rw-r--r--tests/ui/argument-suggestions/issue-109425.rs4
-rw-r--r--tests/ui/argument-suggestions/issue-109425.stderr42
-rw-r--r--tests/ui/argument-suggestions/issue-112507.stderr5
29 files changed, 1385 insertions, 1752 deletions
diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
index 7358a6c6d22..547030a1854 100644
--- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs
@@ -6,13 +6,10 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
-use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::{self, AdtDef, GenericArgsRef, Ty};
 use rustc_middle::{bug, mir};
-use rustc_trait_selection::traits::{
-    ImplSource, Obligation, ObligationCause, ObligationCtxt, SelectionContext,
-};
-use tracing::{instrument, trace};
+use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt};
+use tracing::instrument;
 
 use super::ConstCx;
 
@@ -195,50 +192,8 @@ impl Qualif for NeedsNonConstDrop {
             return false;
         }
 
-        // FIXME(effects): If `destruct` is not a `const_trait`,
-        // or effects are disabled in this crate, then give up.
-        let destruct_def_id = cx.tcx.require_lang_item(LangItem::Destruct, Some(cx.body.span));
-        if !cx.tcx.has_host_param(destruct_def_id) || !cx.tcx.features().effects {
-            return NeedsDrop::in_any_value_of_ty(cx, ty);
-        }
-
-        let obligation = Obligation::new(
-            cx.tcx,
-            ObligationCause::dummy_with_span(cx.body.span),
-            cx.param_env,
-            ty::TraitRef::new(cx.tcx, destruct_def_id, [
-                ty::GenericArg::from(ty),
-                ty::GenericArg::from(cx.tcx.expected_host_effect_param_for_body(cx.def_id())),
-            ]),
-        );
-
-        let infcx = cx.tcx.infer_ctxt().build();
-        let mut selcx = SelectionContext::new(&infcx);
-        let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
-            // If we couldn't select a const destruct candidate, then it's bad
-            return true;
-        };
-
-        trace!(?impl_src);
-
-        if !matches!(
-            impl_src,
-            ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(_)
-        ) {
-            // If our const destruct candidate is not ConstDestruct or implied by the param env,
-            // then it's bad
-            return true;
-        }
-
-        if impl_src.borrow_nested_obligations().is_empty() {
-            return false;
-        }
-
-        // If we had any errors, then it's bad
-        let ocx = ObligationCtxt::new(&infcx);
-        ocx.register_obligations(impl_src.nested_obligations());
-        let errors = ocx.select_all_or_error();
-        !errors.is_empty()
+        // FIXME(effects): Reimplement const drop checking.
+        NeedsDrop::in_any_value_of_ty(cx, ty)
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 7f4ab352ef2..9a2c38e51e2 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -51,7 +51,7 @@ impl<'tcx> Bounds<'tcx> {
         bound_trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
         polarity: ty::PredicatePolarity,
-        constness: ty::BoundConstness,
+        constness: Option<ty::BoundConstness>,
         predicate_filter: PredicateFilter,
     ) {
         let clause = (
@@ -88,19 +88,20 @@ impl<'tcx> Bounds<'tcx> {
         // associated type of `<T as Tr>` and make sure that the effect is compatible.
         let compat_val = match (tcx.def_kind(defining_def_id), constness) {
             // FIXME(effects): revisit the correctness of this
-            (_, ty::BoundConstness::Const) => tcx.consts.false_,
+            (_, Some(ty::BoundConstness::Const)) => tcx.consts.false_,
             // body owners that can have trait bounds
-            (DefKind::Const | DefKind::Fn | DefKind::AssocFn, ty::BoundConstness::ConstIfConst) => {
-                tcx.expected_host_effect_param_for_body(defining_def_id)
-            }
+            (
+                DefKind::Const | DefKind::Fn | DefKind::AssocFn,
+                Some(ty::BoundConstness::ConstIfConst),
+            ) => tcx.expected_host_effect_param_for_body(defining_def_id),
 
-            (_, ty::BoundConstness::NotConst) => {
+            (_, None) => {
                 if !tcx.is_const_trait(bound_trait_ref.def_id()) {
                     return;
                 }
                 tcx.consts.true_
             }
-            (DefKind::Trait, ty::BoundConstness::ConstIfConst) => {
+            (DefKind::Trait, Some(ty::BoundConstness::ConstIfConst)) => {
                 // we are in a trait, where `bound_trait_ref` could be:
                 // (1) a super trait `trait Foo: ~const Bar`.
                 //     - This generates `<Self as Foo>::Effects: TyCompat<<Self as Bar>::Effects>`
@@ -138,7 +139,7 @@ impl<'tcx> Bounds<'tcx> {
                 return;
             }
 
-            (DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => {
+            (DefKind::Impl { of_trait: true }, Some(ty::BoundConstness::ConstIfConst)) => {
                 // this is a where clause on an impl header.
                 // push `<T as Tr>::Effects` into the set for the `Min` bound.
                 let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else {
@@ -172,12 +173,12 @@ impl<'tcx> Bounds<'tcx> {
             //
             // FIXME(effects) this is equality for now, which wouldn't be helpful for a non-const implementor
             // that uses a `Bar` that implements `Trait` with `Maybe` effects.
-            (DefKind::AssocTy, ty::BoundConstness::ConstIfConst) => {
+            (DefKind::AssocTy, Some(ty::BoundConstness::ConstIfConst)) => {
                 // FIXME(effects): implement this
                 return;
             }
             // probably illegal in this position.
-            (_, ty::BoundConstness::ConstIfConst) => {
+            (_, Some(ty::BoundConstness::ConstIfConst)) => {
                 tcx.dcx().span_delayed_bug(span, "invalid `~const` encountered");
                 return;
             }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 8605553f797..4721a3a0cf5 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -171,16 +171,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 hir::GenericBound::Trait(poly_trait_ref) => {
                     let (constness, polarity) = match poly_trait_ref.modifiers {
                         hir::TraitBoundModifier::Const => {
-                            (ty::BoundConstness::Const, ty::PredicatePolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::MaybeConst => {
-                            (ty::BoundConstness::ConstIfConst, ty::PredicatePolarity::Positive)
-                        }
-                        hir::TraitBoundModifier::None => {
-                            (ty::BoundConstness::NotConst, ty::PredicatePolarity::Positive)
+                            (Some(ty::BoundConstness::Const), ty::PredicatePolarity::Positive)
                         }
+                        hir::TraitBoundModifier::MaybeConst => (
+                            Some(ty::BoundConstness::ConstIfConst),
+                            ty::PredicatePolarity::Positive,
+                        ),
+                        hir::TraitBoundModifier::None => (None, ty::PredicatePolarity::Positive),
                         hir::TraitBoundModifier::Negative => {
-                            (ty::BoundConstness::NotConst, ty::PredicatePolarity::Negative)
+                            (None, ty::PredicatePolarity::Negative)
                         }
                         hir::TraitBoundModifier::Maybe => continue,
                     };
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index 2cf97e29060..a1ee120e855 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -51,7 +51,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             } = self.lower_poly_trait_ref(
                 &trait_bound.trait_ref,
                 trait_bound.span,
-                ty::BoundConstness::NotConst,
+                None,
                 ty::PredicatePolarity::Positive,
                 dummy_self,
                 &mut bounds,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 828809726d2..fe0cd572609 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -652,7 +652,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         &self,
         trait_ref: &hir::TraitRef<'tcx>,
         span: Span,
-        constness: ty::BoundConstness,
+        constness: Option<ty::BoundConstness>,
         polarity: ty::PredicatePolarity,
         self_ty: Ty<'tcx>,
         bounds: &mut Bounds<'tcx>,
@@ -675,7 +675,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             Some(self_ty),
         );
 
-        if let ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst = constness
+        if let Some(constness) = constness
             && !self.tcx().is_const_trait(trait_def_id)
         {
             self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 13ba615d4c9..fa6a86c6911 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -537,40 +537,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 //
                 // This check is here because there is currently no way to express a trait bound for `FnDef` types only.
                 if let ty::FnDef(def_id, _args) = *arg_ty.kind() {
-                    let fn_once_def_id =
-                        self.tcx.require_lang_item(hir::LangItem::FnOnce, Some(span));
-                    let fn_once_output_def_id =
-                        self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
-                    if self.tcx.has_host_param(fn_once_def_id) {
-                        let const_param: ty::GenericArg<'tcx> =
-                            ([self.tcx.consts.false_, self.tcx.consts.true_])[idx].into();
-                        self.register_predicate(traits::Obligation::new(
-                            self.tcx,
-                            self.misc(span),
-                            self.param_env,
-                            ty::TraitRef::new(self.tcx, fn_once_def_id, [
-                                arg_ty.into(),
-                                fn_sig.inputs()[0].into(),
-                                const_param,
-                            ]),
-                        ));
-
-                        self.register_predicate(traits::Obligation::new(
-                            self.tcx,
-                            self.misc(span),
-                            self.param_env,
-                            ty::ProjectionPredicate {
-                                projection_term: ty::AliasTerm::new(
-                                    self.tcx,
-                                    fn_once_output_def_id,
-                                    [arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
-                                ),
-                                term: fn_sig.output().into(),
-                            },
-                        ));
-
-                        self.select_obligations_where_possible(|_| {});
-                    } else if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
+                    if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
                         self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
                     }
                 } else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index bf8cc462189..f29d6199a87 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1097,6 +1097,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut only_extras_so_far = errors
             .peek()
             .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
+        let mut prev_extra_idx = None;
         let mut suggestions = vec![];
         while let Some(error) = errors.next() {
             only_extras_so_far &= matches!(error, Error::Extra(_));
@@ -1165,11 +1166,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         //     fn f() {}
                         //   - f(0, 1,)
                         //   + f()
-                        if only_extras_so_far
-                            && !errors
-                                .peek()
-                                .is_some_and(|next_error| matches!(next_error, Error::Extra(_)))
-                        {
+                        let trim_next_comma = match errors.peek() {
+                            Some(Error::Extra(provided_idx))
+                                if only_extras_so_far
+                                    && provided_idx.index() > arg_idx.index() + 1 =>
+                            // If the next Error::Extra ("next") doesn't next to current ("current"),
+                            // fn foo(_: (), _: u32) {}
+                            // - foo("current", (), 1u32, "next")
+                            // + foo((), 1u32)
+                            // If the previous error is not a `Error::Extra`, then do not trim the next comma
+                            // - foo((), "current", 42u32, "next")
+                            // + foo((), 42u32)
+                            {
+                                prev_extra_idx.map_or(true, |prev_extra_idx| {
+                                    prev_extra_idx + 1 == arg_idx.index()
+                                })
+                            }
+                            // If no error left, we need to delete the next comma
+                            None if only_extras_so_far => true,
+                            // Not sure if other error type need to be handled as well
+                            _ => false,
+                        };
+
+                        if trim_next_comma {
                             let next = provided_arg_tys
                                 .get(arg_idx + 1)
                                 .map(|&(_, sp)| sp)
@@ -1192,6 +1211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             SuggestionText::Remove(_) => SuggestionText::Remove(true),
                             _ => SuggestionText::DidYouMean,
                         };
+                        prev_extra_idx = Some(arg_idx.index())
                     }
                 }
                 Error::Missing(expected_idx) => {
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 66035464fa5..05556ae38a8 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -161,9 +161,7 @@ pub enum SelectionCandidate<'tcx> {
 
     /// Implementation of a `Fn`-family trait by one of the anonymous
     /// types generated for a fn pointer type (e.g., `fn(int) -> int`)
-    FnPointerCandidate {
-        fn_host_effect: ty::Const<'tcx>,
-    },
+    FnPointerCandidate,
 
     TraitAliasCandidate,
 
@@ -180,9 +178,6 @@ pub enum SelectionCandidate<'tcx> {
     BuiltinObjectCandidate,
 
     BuiltinUnsizeCandidate,
-
-    /// Implementation of `const Destruct`, optionally from a custom `impl const Drop`.
-    ConstDestructCandidate(Option<DefId>),
 }
 
 /// The result of trait evaluation. The order is important
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7ada5fd93ba..b5495fa282b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1956,7 +1956,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         define_scoped_cx!(self);
 
         match constness {
-            ty::BoundConstness::NotConst => {}
             ty::BoundConstness::Const => {
                 p!("const ");
             }
@@ -2948,7 +2947,10 @@ impl<'tcx> ty::TraitPredicate<'tcx> {
 }
 
 #[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
-pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness);
+pub struct TraitPredPrintWithBoundConstness<'tcx>(
+    ty::TraitPredicate<'tcx>,
+    Option<ty::BoundConstness>,
+);
 
 impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -2966,7 +2968,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
 
     fn print_with_bound_constness(
         self,
-        constness: ty::BoundConstness,
+        constness: Option<ty::BoundConstness>,
     ) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> {
         self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness))
     }
@@ -3206,7 +3208,9 @@ define_print_and_forward_display! {
 
     TraitPredPrintWithBoundConstness<'tcx> {
         p!(print(self.0.trait_ref.self_ty()), ": ");
-        p!(pretty_print_bound_constness(self.1));
+        if let Some(constness) = self.1 {
+            p!(pretty_print_bound_constness(constness));
+        }
         if let ty::PredicatePolarity::Negative = self.0.polarity {
             p!("!");
         }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 0a917120b3b..9a3049f3be6 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -907,24 +907,6 @@ impl<'tcx> TyCtxt<'tcx> {
         }
     }
 
-    /// Constructs generic args for an item, optionally appending a const effect param type
-    pub fn with_opt_host_effect_param(
-        self,
-        caller_def_id: LocalDefId,
-        callee_def_id: DefId,
-        args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
-    ) -> ty::GenericArgsRef<'tcx> {
-        let generics = self.generics_of(callee_def_id);
-        assert_eq!(generics.parent, None);
-
-        let opt_const_param = generics
-            .host_effect_index
-            .is_some()
-            .then(|| ty::GenericArg::from(self.expected_host_effect_param_for_body(caller_def_id)));
-
-        self.mk_args_from_iter(args.into_iter().map(|arg| arg.into()).chain(opt_const_param))
-    }
-
     /// Expand any [weak alias types][weak] contained within the given `value`.
     ///
     /// This should be used over other normalization routines in situations where
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 020c202f965..7170aebee7d 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -454,12 +454,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         };
 
         let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
-        let method = trait_method(
-            self.tcx,
-            eq_def_id,
-            sym::eq,
-            self.tcx.with_opt_host_effect_param(self.def_id, eq_def_id, [compare_ty, compare_ty]),
-        );
+        let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
 
         let bool_ty = self.tcx.types.bool;
         let eq_result = self.temp(bool_ty, source_info.span);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 2c3611afca9..0dfa9168f7c 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -43,7 +43,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
 }
 
 struct ConstToPat<'tcx> {
-    id: hir::HirId,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
 
@@ -62,7 +61,6 @@ impl<'tcx> ConstToPat<'tcx> {
     ) -> Self {
         trace!(?pat_ctxt.typeck_results.hir_owner);
         ConstToPat {
-            id,
             span,
             infcx,
             param_env: pat_ctxt.param_env,
@@ -149,15 +147,7 @@ impl<'tcx> ConstToPat<'tcx> {
             tcx,
             ObligationCause::dummy(),
             self.param_env,
-            ty::TraitRef::new_from_args(
-                tcx,
-                partial_eq_trait_id,
-                tcx.with_opt_host_effect_param(
-                    tcx.hir().enclosing_body_owner(self.id),
-                    partial_eq_trait_id,
-                    [ty, ty],
-                ),
-            ),
+            ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
         );
 
         // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 322421340e9..549beafd196 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -290,7 +290,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         }
 
                         if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop)
-                            && matches!(predicate_constness, ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const)
+                            && matches!(predicate_constness, Some(ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const))
                         {
                             err.note("`~const Drop` was renamed to `~const Destruct`");
                             err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
@@ -2192,7 +2192,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         &self,
         trait_predicate: ty::PolyTraitPredicate<'tcx>,
         message: Option<String>,
-        predicate_constness: ty::BoundConstness,
+        predicate_constness: Option<ty::BoundConstness>,
         append_const_msg: Option<AppendConstMessage>,
         post_message: String,
     ) -> String {
@@ -2200,19 +2200,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             .and_then(|cannot_do_this| {
                 match (predicate_constness, append_const_msg) {
                     // do nothing if predicate is not const
-                    (ty::BoundConstness::NotConst, _) => Some(cannot_do_this),
+                    (None, _) => Some(cannot_do_this),
                     // suggested using default post message
                     (
-                        ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
+                        Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst),
                         Some(AppendConstMessage::Default),
                     ) => Some(format!("{cannot_do_this} in const contexts")),
                     // overridden post message
                     (
-                        ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst,
+                        Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst),
                         Some(AppendConstMessage::Custom(custom_msg, _)),
                     ) => Some(format!("{cannot_do_this}{custom_msg}")),
                     // fallback to generic message
-                    (ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, None) => None,
+                    (Some(ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst), None) => {
+                        None
+                    }
                 }
             })
             .unwrap_or_else(|| {
@@ -2377,26 +2379,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         p: ty::PolyTraitPredicate<'tcx>,
         leaf: ty::PolyTraitPredicate<'tcx>,
         span: Span,
-    ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, ty::BoundConstness) {
+    ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, Option<ty::BoundConstness>)
+    {
         let trait_ref = p.to_poly_trait_ref();
         if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) {
-            return (p, leaf, ty::BoundConstness::NotConst);
+            return (p, leaf, None);
         }
 
         let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) =
             trait_ref.self_ty().no_bound_vars().map(Ty::kind)
         else {
-            return (p, leaf, ty::BoundConstness::NotConst);
+            return (p, leaf, None);
         };
 
         let constness = trait_ref.skip_binder().args.const_at(1);
 
         let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() {
-            ty::BoundConstness::NotConst
+            None
         } else if constness == self.tcx.consts.false_ {
-            ty::BoundConstness::Const
+            Some(ty::BoundConstness::Const)
         } else if matches!(constness.kind(), ty::ConstKind::Param(_)) {
-            ty::BoundConstness::ConstIfConst
+            Some(ty::BoundConstness::ConstIfConst)
         } else {
             self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}"));
         };
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 733baaa99e5..677905a3085 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3701,12 +3701,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         }
                         _ => None,
                     };
-                    // Also add host param, if present
-                    let host = self.tcx.generics_of(trait_pred.def_id()).host_effect_index.map(|idx| trait_pred.skip_binder().trait_ref.args[idx]);
                     let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
                         trait_ref: ty::TraitRef::new(self.tcx,
                             trait_pred.def_id(),
-                            [field_ty].into_iter().chain(trait_args).chain(host),
+                            [field_ty].into_iter().chain(trait_args),
                         ),
                         ..*tr
                     });
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 7f7c9bced18..cc634b65a0b 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1642,24 +1642,9 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
         sig,
     );
 
-    let host_effect_param = match *fn_type.kind() {
-        ty::FnDef(def_id, args) => tcx
-            .generics_of(def_id)
-            .host_effect_index
-            .map_or(tcx.consts.true_, |idx| args.const_at(idx)),
-        ty::FnPtr(..) => tcx.consts.true_,
-        _ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
-    };
-
-    confirm_callable_candidate(
-        selcx,
-        obligation,
-        sig,
-        util::TupleArgumentsFlag::Yes,
-        host_effect_param,
-    )
-    .with_addl_obligations(nested)
-    .with_addl_obligations(obligations)
+    confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
+        .with_addl_obligations(nested)
+        .with_addl_obligations(obligations)
 }
 
 fn confirm_closure_candidate<'cx, 'tcx>(
@@ -1739,16 +1724,9 @@ fn confirm_closure_candidate<'cx, 'tcx>(
 
     debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate");
 
-    confirm_callable_candidate(
-        selcx,
-        obligation,
-        closure_sig,
-        util::TupleArgumentsFlag::No,
-        // FIXME(effects): This doesn't handle const closures correctly!
-        selcx.tcx().consts.true_,
-    )
-    .with_addl_obligations(nested)
-    .with_addl_obligations(obligations)
+    confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No)
+        .with_addl_obligations(nested)
+        .with_addl_obligations(obligations)
 }
 
 fn confirm_callable_candidate<'cx, 'tcx>(
@@ -1756,7 +1734,6 @@ fn confirm_callable_candidate<'cx, 'tcx>(
     obligation: &ProjectionTermObligation<'tcx>,
     fn_sig: ty::PolyFnSig<'tcx>,
     flag: util::TupleArgumentsFlag,
-    fn_host_effect: ty::Const<'tcx>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
 
@@ -1771,7 +1748,6 @@ fn confirm_callable_candidate<'cx, 'tcx>(
         obligation.predicate.self_ty(),
         fn_sig,
         flag,
-        fn_host_effect,
     )
     .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
         projection_term: ty::AliasTerm::new_from_args(tcx, fn_once_output_def_id, trait_ref.args),
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index aa313a526c1..ac38c9e24a2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -543,23 +543,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // Provide an impl, but only for suitable `fn` pointers.
             ty::FnPtr(sig_tys, hdr) => {
                 if sig_tys.with(hdr).is_fn_trait_compatible() {
-                    candidates
-                        .vec
-                        .push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
+                    candidates.vec.push(FnPointerCandidate);
                 }
             }
             // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396).
-            ty::FnDef(def_id, args) => {
+            ty::FnDef(def_id, _args) => {
                 let tcx = self.tcx();
                 if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible()
                     && tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                 {
-                    candidates.vec.push(FnPointerCandidate {
-                        fn_host_effect: tcx
-                            .generics_of(def_id)
-                            .host_effect_index
-                            .map_or(tcx.consts.true_, |idx| args.const_at(idx)),
-                    });
+                    candidates.vec.push(FnPointerCandidate);
                 }
             }
             _ => {}
@@ -1170,103 +1163,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn assemble_const_destruct_candidates(
         &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
+        _obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        // If the predicate is `~const Destruct` in a non-const environment, we don't actually need
-        // to check anything. We'll short-circuit checking any obligations in confirmation, too.
-        let Some(host_effect_index) =
-            self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
-        else {
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
-            return;
-        };
-        // If the obligation has `host = true`, then the obligation is non-const and it's always
-        // trivially implemented.
-        if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index)
-            == self.tcx().consts.true_
-        {
-            candidates.vec.push(BuiltinCandidate { has_nested: false });
-            return;
-        }
-
-        let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
-        match self_ty.kind() {
-            ty::Alias(..)
-            | ty::Dynamic(..)
-            | ty::Error(_)
-            | ty::Bound(..)
-            | ty::Param(_)
-            | ty::Placeholder(_) => {
-                // We don't know if these are `~const Destruct`, at least
-                // not structurally... so don't push a candidate.
-            }
-
-            ty::Bool
-            | ty::Char
-            | ty::Int(_)
-            | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Infer(ty::IntVar(_))
-            | ty::Infer(ty::FloatVar(_))
-            | ty::Str
-            | ty::RawPtr(_, _)
-            | ty::Ref(..)
-            | ty::FnDef(..)
-            | ty::FnPtr(..)
-            | ty::Never
-            | ty::Foreign(_)
-            | ty::Array(..)
-            | ty::Pat(..)
-            | ty::Slice(_)
-            | ty::Closure(..)
-            | ty::CoroutineClosure(..)
-            | ty::Coroutine(..)
-            | ty::Tuple(_)
-            | ty::CoroutineWitness(..) => {
-                // These are built-in, and cannot have a custom `impl const Destruct`.
-                candidates.vec.push(ConstDestructCandidate(None));
-            }
-
-            ty::Adt(..) => {
-                let mut relevant_impl = None;
-                self.tcx().for_each_relevant_impl(
-                    self.tcx().require_lang_item(LangItem::Drop, None),
-                    obligation.predicate.skip_binder().trait_ref.self_ty(),
-                    |impl_def_id| {
-                        if let Some(old_impl_def_id) = relevant_impl {
-                            self.tcx()
-                                .dcx()
-                                .struct_span_err(
-                                    self.tcx().def_span(impl_def_id),
-                                    "multiple drop impls found",
-                                )
-                                .with_span_note(
-                                    self.tcx().def_span(old_impl_def_id),
-                                    "other impl here",
-                                )
-                                .delay_as_bug();
-                        }
-
-                        relevant_impl = Some(impl_def_id);
-                    },
-                );
-
-                if let Some(impl_def_id) = relevant_impl {
-                    // Check that `impl Drop` is actually const, if there is a custom impl
-                    if self.tcx().constness(impl_def_id) == hir::Constness::Const {
-                        candidates.vec.push(ConstDestructCandidate(Some(impl_def_id)));
-                    }
-                } else {
-                    // Otherwise check the ADT like a built-in type (structurally)
-                    candidates.vec.push(ConstDestructCandidate(None));
-                }
-            }
-
-            ty::Infer(_) => {
-                candidates.ambiguous = true;
-            }
-        }
+        // FIXME(effects): Destruct is not const yet, and it is implemented
+        // by all types today in non-const setting.
+        candidates.vec.push(BuiltinCandidate { has_nested: false });
     }
 
     fn assemble_candidate_for_tuple(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index f78cd6c1aa0..9a49fd7e77e 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -28,9 +28,9 @@ use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
 use crate::traits::util::{self, closure_trait_ref_and_return_type};
 use crate::traits::{
-    ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation,
-    ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError,
-    SignatureMismatch, TraitDynIncompatible, TraitObligation, Unimplemented,
+    ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause,
+    PolyTraitObligation, PredicateObligation, Selection, SelectionError, SignatureMismatch,
+    TraitDynIncompatible, TraitObligation, Unimplemented,
 };
 
 impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
@@ -109,8 +109,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator)
             }
 
-            FnPointerCandidate { fn_host_effect } => {
-                let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?;
+            FnPointerCandidate => {
+                let data = self.confirm_fn_pointer_candidate(obligation)?;
                 ImplSource::Builtin(BuiltinImplSource::Misc, data)
             }
 
@@ -131,11 +131,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             TraitUpcastingUnsizeCandidate(idx) => {
                 self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
             }
-
-            ConstDestructCandidate(def_id) => {
-                let data = self.confirm_const_destruct_candidate(obligation, def_id)?;
-                ImplSource::Builtin(BuiltinImplSource::Misc, data)
-            }
         };
 
         // The obligations returned by confirmation are recursively evaluated
@@ -711,7 +706,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_fn_pointer_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
-        fn_host_effect: ty::Const<'tcx>,
     ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         debug!(?obligation, "confirm_fn_pointer_candidate");
         let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate);
@@ -725,7 +719,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             self_ty,
             sig,
             util::TupleArgumentsFlag::Yes,
-            fn_host_effect,
         )
         .map_bound(|(trait_ref, _)| trait_ref);
 
@@ -907,11 +900,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty());
 
         let trait_ref = match *self_ty.kind() {
-            ty::Closure(..) => self.closure_trait_ref_unnormalized(
-                self_ty,
-                obligation.predicate.def_id(),
-                self.tcx().consts.true_,
-            ),
+            ty::Closure(..) => {
+                self.closure_trait_ref_unnormalized(self_ty, obligation.predicate.def_id())
+            }
             ty::CoroutineClosure(_, args) => {
                 args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
                     ty::TraitRef::new(self.tcx(), obligation.predicate.def_id(), [
@@ -1344,170 +1335,4 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("source: {source}, target: {target}"),
         })
     }
-
-    fn confirm_const_destruct_candidate(
-        &mut self,
-        obligation: &PolyTraitObligation<'tcx>,
-        impl_def_id: Option<DefId>,
-    ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
-        let Some(host_effect_index) =
-            self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index
-        else {
-            bug!()
-        };
-        let host_effect_param: ty::GenericArg<'tcx> =
-            obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into();
-
-        let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None);
-
-        let tcx = self.tcx();
-        let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
-
-        let mut nested = PredicateObligations::new();
-        let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
-
-        // If we have a custom `impl const Drop`, then
-        // first check it like a regular impl candidate.
-        // This is copied from confirm_impl_candidate but remaps the predicate to `~const Drop` beforehand.
-        if let Some(impl_def_id) = impl_def_id {
-            let mut new_obligation = obligation.clone();
-            new_obligation.predicate = new_obligation.predicate.map_bound(|mut trait_pred| {
-                trait_pred.trait_ref.def_id = drop_trait;
-                trait_pred
-            });
-            let args = self.rematch_impl(impl_def_id, &new_obligation);
-            debug!(?args, "impl args");
-
-            let cause = obligation.derived_cause(|derived| {
-                ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause {
-                    derived,
-                    impl_or_alias_def_id: impl_def_id,
-                    impl_def_predicate_index: None,
-                    span: obligation.cause.span,
-                }))
-            });
-            let obligations = ensure_sufficient_stack(|| {
-                self.vtable_impl(
-                    impl_def_id,
-                    args,
-                    &cause,
-                    new_obligation.recursion_depth + 1,
-                    new_obligation.param_env,
-                    obligation.predicate,
-                )
-            });
-            nested.extend(obligations.nested);
-        }
-
-        // We want to confirm the ADT's fields if we have an ADT
-        let mut stack = match *self_ty.skip_binder().kind() {
-            ty::Adt(def, args) => def.all_fields().map(|f| f.ty(tcx, args)).collect(),
-            _ => vec![self_ty.skip_binder()],
-        };
-
-        while let Some(nested_ty) = stack.pop() {
-            match *nested_ty.kind() {
-                // We know these types are trivially drop
-                ty::Bool
-                | ty::Char
-                | ty::Int(_)
-                | ty::Uint(_)
-                | ty::Float(_)
-                | ty::Infer(ty::IntVar(_))
-                | ty::Infer(ty::FloatVar(_))
-                | ty::Str
-                | ty::RawPtr(_, _)
-                | ty::Ref(..)
-                | ty::FnDef(..)
-                | ty::FnPtr(..)
-                | ty::Never
-                | ty::Foreign(_) => {}
-
-                // `ManuallyDrop` is trivially drop
-                ty::Adt(def, _) if def.is_manually_drop() => {}
-
-                // These types are built-in, so we can fast-track by registering
-                // nested predicates for their constituent type(s)
-                ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => {
-                    stack.push(ty);
-                }
-                ty::Tuple(tys) => {
-                    stack.extend(tys.iter());
-                }
-                ty::Closure(_, args) => {
-                    stack.push(args.as_closure().tupled_upvars_ty());
-                }
-                ty::Coroutine(_, args) => {
-                    let coroutine = args.as_coroutine();
-                    stack.extend([coroutine.tupled_upvars_ty(), coroutine.witness()]);
-                }
-                ty::CoroutineWitness(def_id, args) => {
-                    let tcx = self.tcx();
-                    stack.extend(tcx.bound_coroutine_hidden_types(def_id).map(|bty| {
-                        self.infcx.enter_forall_and_leak_universe(bty.instantiate(tcx, args))
-                    }))
-                }
-
-                // If we have a projection type, make sure to normalize it so we replace it
-                // with a fresh infer variable
-                ty::Alias(ty::Projection | ty::Inherent, ..) => {
-                    let predicate = normalize_with_depth_to(
-                        self,
-                        obligation.param_env,
-                        cause.clone(),
-                        obligation.recursion_depth + 1,
-                        self_ty.rebind(ty::TraitPredicate {
-                            trait_ref: ty::TraitRef::new(
-                                self.tcx(),
-                                self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
-                                [nested_ty.into(), host_effect_param],
-                            ),
-                            polarity: ty::PredicatePolarity::Positive,
-                        }),
-                        &mut nested,
-                    );
-
-                    nested.push(Obligation::with_depth(
-                        tcx,
-                        cause.clone(),
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        predicate,
-                    ));
-                }
-
-                // If we have any other type (e.g. an ADT), just register a nested obligation
-                // since it's either not `const Drop` (and we raise an error during selection),
-                // or it's an ADT (and we need to check for a custom impl during selection)
-                ty::Error(_)
-                | ty::Dynamic(..)
-                | ty::CoroutineClosure(..)
-                | ty::Param(_)
-                | ty::Bound(..)
-                | ty::Adt(..)
-                | ty::Alias(ty::Opaque | ty::Weak, _)
-                | ty::Infer(_)
-                | ty::Placeholder(_) => {
-                    let predicate = self_ty.rebind(ty::TraitPredicate {
-                        trait_ref: ty::TraitRef::new(
-                            self.tcx(),
-                            self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
-                            [nested_ty.into(), host_effect_param],
-                        ),
-                        polarity: ty::PredicatePolarity::Positive,
-                    });
-
-                    nested.push(Obligation::with_depth(
-                        tcx,
-                        cause.clone(),
-                        obligation.recursion_depth + 1,
-                        obligation.param_env,
-                        predicate,
-                    ));
-                }
-            }
-        }
-
-        Ok(nested)
-    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 621babe9104..4757430a21c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1831,12 +1831,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => DropVictim::No,
 
             // (*)
-            (BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_), _) => {
-                DropVictim::Yes
-            }
-            (_, BuiltinCandidate { has_nested: false } | ConstDestructCandidate(_)) => {
-                DropVictim::No
-            }
+            (BuiltinCandidate { has_nested: false }, _) => DropVictim::Yes,
+            (_, BuiltinCandidate { has_nested: false }) => DropVictim::No,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
                 let same_except_bound_vars = other.skip_binder().trait_ref
@@ -1855,11 +1851,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 }
             }
 
-            // Drop otherwise equivalent non-const fn pointer candidates
-            (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => {
-                DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_)
-            }
-
             (
                 ParamCandidate(other_cand),
                 ImplCandidate(..)
@@ -2766,7 +2757,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
         &mut self,
         self_ty: Ty<'tcx>,
         fn_trait_def_id: DefId,
-        fn_host_effect: ty::Const<'tcx>,
     ) -> ty::PolyTraitRef<'tcx> {
         let ty::Closure(_, args) = *self_ty.kind() else {
             bug!("expected closure, found {self_ty}");
@@ -2779,7 +2769,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             self_ty,
             closure_sig,
             util::TupleArgumentsFlag::No,
-            fn_host_effect,
         )
         .map_bound(|(trait_ref, _)| trait_ref)
     }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index aed2e3d61aa..b7a2f20b769 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -215,22 +215,13 @@ pub(crate) fn closure_trait_ref_and_return_type<'tcx>(
     self_ty: Ty<'tcx>,
     sig: ty::PolyFnSig<'tcx>,
     tuple_arguments: TupleArgumentsFlag,
-    fn_host_effect: ty::Const<'tcx>,
 ) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
     assert!(!self_ty.has_escaping_bound_vars());
     let arguments_tuple = match tuple_arguments {
         TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
         TupleArgumentsFlag::Yes => Ty::new_tup(tcx, sig.skip_binder().inputs()),
     };
-    let trait_ref = if tcx.has_host_param(fn_trait_def_id) {
-        ty::TraitRef::new(tcx, fn_trait_def_id, [
-            ty::GenericArg::from(self_ty),
-            ty::GenericArg::from(arguments_tuple),
-            ty::GenericArg::from(fn_host_effect),
-        ])
-    } else {
-        ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple])
-    };
+    let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
     sig.map_bound(|sig| (trait_ref, sig.output()))
 }
 
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 8146181df6c..b613505f826 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -726,9 +726,9 @@ pub struct CoercePredicate<I: Interner> {
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))]
 pub enum BoundConstness {
-    /// `Type: Trait`
-    NotConst,
     /// `Type: const Trait`
+    ///
+    /// A bound is required to be unconditionally const, even in a runtime function.
     Const,
     /// `Type: ~const Trait`
     ///
@@ -739,7 +739,6 @@ pub enum BoundConstness {
 impl BoundConstness {
     pub fn as_str(self) -> &'static str {
         match self {
-            Self::NotConst => "",
             Self::Const => "const",
             Self::ConstIfConst => "~const",
         }
@@ -749,7 +748,6 @@ impl BoundConstness {
 impl fmt::Display for BoundConstness {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self::NotConst => f.write_str("normal"),
             Self::Const => f.write_str("const"),
             Self::ConstIfConst => f.write_str("~const"),
         }
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
new file mode 100644
index 00000000000..c3d0994f164
--- /dev/null
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -0,0 +1,1220 @@
+use std::env;
+use std::ffi::{OsStr, OsString};
+use std::path::{Path, PathBuf};
+
+use super::{Builder, Kind};
+use crate::core::build_steps::tool::SourceType;
+use crate::core::build_steps::{compile, test};
+use crate::core::config::SplitDebuginfo;
+use crate::core::config::flags::Color;
+use crate::utils::helpers::{
+    self, LldThreads, add_link_lib_path, check_cfg_arg, linker_args, linker_flags,
+};
+use crate::{
+    BootstrapCommand, CLang, Compiler, DocTests, DryRun, EXTRA_CHECK_CFGS, GitRepo, Mode,
+    TargetSelection, command, prepare_behaviour_dump_dir, t,
+};
+
+/// Represents flag values in `String` form with whitespace delimiter to pass it to the compiler
+/// later.
+///
+/// `-Z crate-attr` flags will be applied recursively on the target code using the
+/// `rustc_parse::parser::Parser`. See `rustc_builtin_macros::cmdline_attrs::inject` for more
+/// information.
+#[derive(Debug, Clone)]
+struct Rustflags(String, TargetSelection);
+
+impl Rustflags {
+    fn new(target: TargetSelection) -> Rustflags {
+        let mut ret = Rustflags(String::new(), target);
+        ret.propagate_cargo_env("RUSTFLAGS");
+        ret
+    }
+
+    /// By default, cargo will pick up on various variables in the environment. However, bootstrap
+    /// reuses those variables to pass additional flags to rustdoc, so by default they get
+    /// overridden. Explicitly add back any previous value in the environment.
+    ///
+    /// `prefix` is usually `RUSTFLAGS` or `RUSTDOCFLAGS`.
+    fn propagate_cargo_env(&mut self, prefix: &str) {
+        // Inherit `RUSTFLAGS` by default ...
+        self.env(prefix);
+
+        // ... and also handle target-specific env RUSTFLAGS if they're configured.
+        let target_specific = format!("CARGO_TARGET_{}_{}", crate::envify(&self.1.triple), prefix);
+        self.env(&target_specific);
+    }
+
+    fn env(&mut self, env: &str) {
+        if let Ok(s) = env::var(env) {
+            for part in s.split(' ') {
+                self.arg(part);
+            }
+        }
+    }
+
+    fn arg(&mut self, arg: &str) -> &mut Self {
+        assert_eq!(arg.split(' ').count(), 1);
+        if !self.0.is_empty() {
+            self.0.push(' ');
+        }
+        self.0.push_str(arg);
+        self
+    }
+}
+
+/// Flags that are passed to the `rustc` shim binary. These flags will only be applied when
+/// compiling host code, i.e. when `--target` is unset.
+#[derive(Debug, Default)]
+struct HostFlags {
+    rustc: Vec<String>,
+}
+
+impl HostFlags {
+    const SEPARATOR: &'static str = " ";
+
+    /// Adds a host rustc flag.
+    fn arg<S: Into<String>>(&mut self, flag: S) {
+        let value = flag.into().trim().to_string();
+        assert!(!value.contains(Self::SEPARATOR));
+        self.rustc.push(value);
+    }
+
+    /// Encodes all the flags into a single string.
+    fn encode(self) -> String {
+        self.rustc.join(Self::SEPARATOR)
+    }
+}
+
+#[derive(Debug)]
+pub struct Cargo {
+    command: BootstrapCommand,
+    compiler: Compiler,
+    target: TargetSelection,
+    rustflags: Rustflags,
+    rustdocflags: Rustflags,
+    hostflags: HostFlags,
+    allow_features: String,
+}
+
+impl Cargo {
+    /// Calls [`Builder::cargo`] and [`Cargo::configure_linker`] to prepare an invocation of `cargo`
+    /// to be run.
+    pub fn new(
+        builder: &Builder<'_>,
+        compiler: Compiler,
+        mode: Mode,
+        source_type: SourceType,
+        target: TargetSelection,
+        cmd_kind: Kind,
+    ) -> Cargo {
+        let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind);
+
+        match cmd_kind {
+            // No need to configure the target linker for these command types,
+            // as they don't invoke rustc at all.
+            Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {}
+            _ => {
+                cargo.configure_linker(builder);
+            }
+        }
+
+        cargo
+    }
+
+    pub fn into_cmd(self) -> BootstrapCommand {
+        self.into()
+    }
+
+    /// Same as [`Cargo::new`] except this one doesn't configure the linker with
+    /// [`Cargo::configure_linker`].
+    pub fn new_for_mir_opt_tests(
+        builder: &Builder<'_>,
+        compiler: Compiler,
+        mode: Mode,
+        source_type: SourceType,
+        target: TargetSelection,
+        cmd_kind: Kind,
+    ) -> Cargo {
+        builder.cargo(compiler, mode, source_type, target, cmd_kind)
+    }
+
+    pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
+        self.rustdocflags.arg(arg);
+        self
+    }
+
+    pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
+        self.rustflags.arg(arg);
+        self
+    }
+
+    pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo {
+        self.command.arg(arg.as_ref());
+        self
+    }
+
+    pub fn args<I, S>(&mut self, args: I) -> &mut Cargo
+    where
+        I: IntoIterator<Item = S>,
+        S: AsRef<OsStr>,
+    {
+        for arg in args {
+            self.arg(arg.as_ref());
+        }
+        self
+    }
+
+    /// Add an env var to the cargo command instance. Note that `RUSTFLAGS`/`RUSTDOCFLAGS` must go
+    /// through [`Cargo::rustdocflags`] and [`Cargo::rustflags`] because inconsistent `RUSTFLAGS`
+    /// and `RUSTDOCFLAGS` usages will trigger spurious rebuilds.
+    pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
+        assert_ne!(key.as_ref(), "RUSTFLAGS");
+        assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
+        self.command.env(key.as_ref(), value.as_ref());
+        self
+    }
+
+    pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) {
+        builder.add_rustc_lib_path(self.compiler, &mut self.command);
+    }
+
+    pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
+        self.command.current_dir(dir);
+        self
+    }
+
+    /// Adds nightly-only features that this invocation is allowed to use.
+    ///
+    /// By default, all nightly features are allowed. Once this is called, it will be restricted to
+    /// the given set.
+    pub fn allow_features(&mut self, features: &str) -> &mut Cargo {
+        if !self.allow_features.is_empty() {
+            self.allow_features.push(',');
+        }
+        self.allow_features.push_str(features);
+        self
+    }
+
+    fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
+        let target = self.target;
+        let compiler = self.compiler;
+
+        // Dealing with rpath here is a little special, so let's go into some
+        // detail. First off, `-rpath` is a linker option on Unix platforms
+        // which adds to the runtime dynamic loader path when looking for
+        // dynamic libraries. We use this by default on Unix platforms to ensure
+        // that our nightlies behave the same on Windows, that is they work out
+        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
+        // table of `config.toml`
+        //
+        // Ok, so the astute might be wondering "why isn't `-C rpath` used
+        // here?" and that is indeed a good question to ask. This codegen
+        // option is the compiler's current interface to generating an rpath.
+        // Unfortunately it doesn't quite suffice for us. The flag currently
+        // takes no value as an argument, so the compiler calculates what it
+        // should pass to the linker as `-rpath`. This unfortunately is based on
+        // the **compile time** directory structure which when building with
+        // Cargo will be very different than the runtime directory structure.
+        //
+        // All that's a really long winded way of saying that if we use
+        // `-Crpath` then the executables generated have the wrong rpath of
+        // something like `$ORIGIN/deps` when in fact the way we distribute
+        // rustc requires the rpath to be `$ORIGIN/../lib`.
+        //
+        // So, all in all, to set up the correct rpath we pass the linker
+        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
+        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
+        // to change a flag in a binary?
+        if builder.config.rpath_enabled(target) && helpers::use_host_linker(target) {
+            let libdir = builder.sysroot_libdir_relative(compiler).to_str().unwrap();
+            let rpath = if target.contains("apple") {
+                // Note that we need to take one extra step on macOS to also pass
+                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
+                // do that we pass a weird flag to the compiler to get it to do
+                // so. Note that this is definitely a hack, and we should likely
+                // flesh out rpath support more fully in the future.
+                self.rustflags.arg("-Zosx-rpath-install-name");
+                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
+            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
+                self.rustflags.arg("-Clink-args=-Wl,-z,origin");
+                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
+            } else {
+                None
+            };
+            if let Some(rpath) = rpath {
+                self.rustflags.arg(&format!("-Clink-args={rpath}"));
+            }
+        }
+
+        for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
+            self.hostflags.arg(&arg);
+        }
+
+        if let Some(target_linker) = builder.linker(target) {
+            let target = crate::envify(&target.triple);
+            self.command.env(format!("CARGO_TARGET_{target}_LINKER"), target_linker);
+        }
+        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
+        // `linker_args` here.
+        for flag in linker_flags(builder, target, LldThreads::Yes) {
+            self.rustflags.arg(&flag);
+        }
+        for arg in linker_args(builder, target, LldThreads::Yes) {
+            self.rustdocflags.arg(&arg);
+        }
+
+        if !builder.config.dry_run()
+            && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
+        {
+            self.rustflags.arg("-Clink-arg=-gz");
+        }
+
+        // Throughout the build Cargo can execute a number of build scripts
+        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
+        // obtained previously to those build scripts.
+        // Build scripts use either the `cc` crate or `configure/make` so we pass
+        // the options through environment variables that are fetched and understood by both.
+        //
+        // FIXME: the guard against msvc shouldn't need to be here
+        if target.is_msvc() {
+            if let Some(ref cl) = builder.config.llvm_clang_cl {
+                // FIXME: There is a bug in Clang 18 when building for ARM64:
+                // https://github.com/llvm/llvm-project/pull/81849. This is
+                // fixed in LLVM 19, but can't be backported.
+                if !target.starts_with("aarch64") && !target.starts_with("arm64ec") {
+                    self.command.env("CC", cl).env("CXX", cl);
+                }
+            }
+        } else {
+            let ccache = builder.config.ccache.as_ref();
+            let ccacheify = |s: &Path| {
+                let ccache = match ccache {
+                    Some(ref s) => s,
+                    None => return s.display().to_string(),
+                };
+                // FIXME: the cc-rs crate only recognizes the literal strings
+                // `ccache` and `sccache` when doing caching compilations, so we
+                // mirror that here. It should probably be fixed upstream to
+                // accept a new env var or otherwise work with custom ccache
+                // vars.
+                match &ccache[..] {
+                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
+                    _ => s.display().to_string(),
+                }
+            };
+            let triple_underscored = target.triple.replace('-', "_");
+            let cc = ccacheify(&builder.cc(target));
+            self.command.env(format!("CC_{triple_underscored}"), &cc);
+
+            let cflags = builder.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
+            self.command.env(format!("CFLAGS_{triple_underscored}"), &cflags);
+
+            if let Some(ar) = builder.ar(target) {
+                let ranlib = format!("{} s", ar.display());
+                self.command
+                    .env(format!("AR_{triple_underscored}"), ar)
+                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
+            }
+
+            if let Ok(cxx) = builder.cxx(target) {
+                let cxx = ccacheify(&cxx);
+                let cxxflags = builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
+                self.command
+                    .env(format!("CXX_{triple_underscored}"), &cxx)
+                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
+            }
+        }
+
+        self
+    }
+}
+
+impl From<Cargo> for BootstrapCommand {
+    fn from(mut cargo: Cargo) -> BootstrapCommand {
+        let rustflags = &cargo.rustflags.0;
+        if !rustflags.is_empty() {
+            cargo.command.env("RUSTFLAGS", rustflags);
+        }
+
+        let rustdocflags = &cargo.rustdocflags.0;
+        if !rustdocflags.is_empty() {
+            cargo.command.env("RUSTDOCFLAGS", rustdocflags);
+        }
+
+        let encoded_hostflags = cargo.hostflags.encode();
+        if !encoded_hostflags.is_empty() {
+            cargo.command.env("RUSTC_HOST_FLAGS", encoded_hostflags);
+        }
+
+        if !cargo.allow_features.is_empty() {
+            cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
+        }
+        cargo.command
+    }
+}
+
+impl Builder<'_> {
+    /// Like [`Builder::cargo`], but only passes flags that are valid for all commands.
+    pub fn bare_cargo(
+        &self,
+        compiler: Compiler,
+        mode: Mode,
+        target: TargetSelection,
+        cmd_kind: Kind,
+    ) -> BootstrapCommand {
+        let mut cargo = match cmd_kind {
+            Kind::Clippy => {
+                let mut cargo = self.cargo_clippy_cmd(compiler);
+                cargo.arg(cmd_kind.as_str());
+                cargo
+            }
+            Kind::MiriSetup => {
+                let mut cargo = self.cargo_miri_cmd(compiler);
+                cargo.arg("miri").arg("setup");
+                cargo
+            }
+            Kind::MiriTest => {
+                let mut cargo = self.cargo_miri_cmd(compiler);
+                cargo.arg("miri").arg("test");
+                cargo
+            }
+            _ => {
+                let mut cargo = command(&self.initial_cargo);
+                cargo.arg(cmd_kind.as_str());
+                cargo
+            }
+        };
+
+        // Run cargo from the source root so it can find .cargo/config.
+        // This matters when using vendoring and the working directory is outside the repository.
+        cargo.current_dir(&self.src);
+
+        let out_dir = self.stage_out(compiler, mode);
+        cargo.env("CARGO_TARGET_DIR", &out_dir);
+
+        // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
+        // from out of tree it shouldn't matter, since x.py is only used for
+        // building in-tree.
+        let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
+        match self.build.config.color {
+            Color::Always => {
+                cargo.arg("--color=always");
+                for log in &color_logs {
+                    cargo.env(log, "always");
+                }
+            }
+            Color::Never => {
+                cargo.arg("--color=never");
+                for log in &color_logs {
+                    cargo.env(log, "never");
+                }
+            }
+            Color::Auto => {} // nothing to do
+        }
+
+        if cmd_kind != Kind::Install {
+            cargo.arg("--target").arg(target.rustc_target_arg());
+        } else {
+            assert_eq!(target, compiler.host);
+        }
+
+        if self.config.rust_optimize.is_release() &&
+        // cargo bench/install do not accept `--release` and miri doesn't want it
+        !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest)
+        {
+            cargo.arg("--release");
+        }
+
+        // Remove make-related flags to ensure Cargo can correctly set things up
+        cargo.env_remove("MAKEFLAGS");
+        cargo.env_remove("MFLAGS");
+
+        cargo
+    }
+
+    /// This will create a [`BootstrapCommand`] that represents a pending execution of cargo. This
+    /// cargo will be configured to use `compiler` as the actual rustc compiler, its output will be
+    /// scoped by `mode`'s output directory, it will pass the `--target` flag for the specified
+    /// `target`, and will be executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for
+    /// commands to be run with Miri.
+    fn cargo(
+        &self,
+        compiler: Compiler,
+        mode: Mode,
+        source_type: SourceType,
+        target: TargetSelection,
+        cmd_kind: Kind,
+    ) -> Cargo {
+        let mut cargo = self.bare_cargo(compiler, mode, target, cmd_kind);
+        let out_dir = self.stage_out(compiler, mode);
+
+        let mut hostflags = HostFlags::default();
+
+        // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
+        // so we need to explicitly clear out if they've been updated.
+        for backend in self.codegen_backends(compiler) {
+            self.clear_if_dirty(&out_dir, &backend);
+        }
+
+        if cmd_kind == Kind::Doc {
+            let my_out = match mode {
+                // This is the intended out directory for compiler documentation.
+                Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
+                Mode::Std => {
+                    if self.config.cmd.json() {
+                        out_dir.join(target).join("json-doc")
+                    } else {
+                        out_dir.join(target).join("doc")
+                    }
+                }
+                _ => panic!("doc mode {mode:?} not expected"),
+            };
+            let rustdoc = self.rustdoc(compiler);
+            self.clear_if_dirty(&my_out, &rustdoc);
+        }
+
+        let profile_var = |name: &str| {
+            let profile = if self.config.rust_optimize.is_release() { "RELEASE" } else { "DEV" };
+            format!("CARGO_PROFILE_{}_{}", profile, name)
+        };
+
+        // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
+        // needs to not accidentally link to libLLVM in stage0/lib.
+        cargo.env("REAL_LIBRARY_PATH_VAR", helpers::dylib_path_var());
+        if let Some(e) = env::var_os(helpers::dylib_path_var()) {
+            cargo.env("REAL_LIBRARY_PATH", e);
+        }
+
+        // Set a flag for `check`/`clippy`/`fix`, so that certain build
+        // scripts can do less work (i.e. not building/requiring LLVM).
+        if matches!(cmd_kind, Kind::Check | Kind::Clippy | Kind::Fix) {
+            // If we've not yet built LLVM, or it's stale, then bust
+            // the rustc_llvm cache. That will always work, even though it
+            // may mean that on the next non-check build we'll need to rebuild
+            // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
+            // of work comparatively, and we'd likely need to rebuild it anyway,
+            // so that's okay.
+            if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target, false)
+                .should_build()
+            {
+                cargo.env("RUST_CHECK", "1");
+            }
+        }
+
+        let stage = if compiler.stage == 0 && self.local_rebuild {
+            // Assume the local-rebuild rustc already has stage1 features.
+            1
+        } else {
+            compiler.stage
+        };
+
+        // We synthetically interpret a stage0 compiler used to build tools as a
+        // "raw" compiler in that it's the exact snapshot we download. Normally
+        // the stage0 build means it uses libraries build by the stage0
+        // compiler, but for tools we just use the precompiled libraries that
+        // we've downloaded
+        let use_snapshot = mode == Mode::ToolBootstrap;
+        assert!(!use_snapshot || stage == 0 || self.local_rebuild);
+
+        let maybe_sysroot = self.sysroot(compiler);
+        let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
+        let libdir = self.rustc_libdir(compiler);
+
+        let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
+        if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
+            println!("using sysroot {sysroot_str}");
+        }
+
+        let mut rustflags = Rustflags::new(target);
+        if stage != 0 {
+            if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
+                cargo.args(s.split_whitespace());
+            }
+            rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
+        } else {
+            if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") {
+                cargo.args(s.split_whitespace());
+            }
+            rustflags.env("RUSTFLAGS_BOOTSTRAP");
+            rustflags.arg("--cfg=bootstrap");
+        }
+
+        if cmd_kind == Kind::Clippy {
+            // clippy overwrites sysroot if we pass it to cargo.
+            // Pass it directly to clippy instead.
+            // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
+            // so it has no way of knowing the sysroot.
+            rustflags.arg("--sysroot");
+            rustflags.arg(sysroot_str);
+        }
+
+        let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling {
+            Some(setting) => {
+                // If an explicit setting is given, use that
+                setting
+            }
+            None => {
+                if mode == Mode::Std {
+                    // The standard library defaults to the legacy scheme
+                    false
+                } else {
+                    // The compiler and tools default to the new scheme
+                    true
+                }
+            }
+        };
+
+        // By default, windows-rs depends on a native library that doesn't get copied into the
+        // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
+        // library unnecessary. This can be removed when windows-rs enables raw-dylib
+        // unconditionally.
+        if let Mode::Rustc | Mode::ToolRustc = mode {
+            rustflags.arg("--cfg=windows_raw_dylib");
+        }
+
+        if use_new_symbol_mangling {
+            rustflags.arg("-Csymbol-mangling-version=v0");
+        } else {
+            rustflags.arg("-Csymbol-mangling-version=legacy");
+        }
+
+        // FIXME: the following components don't build with `-Zrandomize-layout` yet:
+        // - wasm-component-ld, due to the `wast`crate
+        // - rust-analyzer, due to the rowan crate
+        // so we exclude entire categories of steps here due to lack of fine-grained control over
+        // rustflags.
+        if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc {
+            rustflags.arg("-Zrandomize-layout");
+        }
+
+        // Enable compile-time checking of `cfg` names, values and Cargo `features`.
+        //
+        // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
+        // backtrace, core_simd, std_float, ...), those dependencies have their own
+        // features but cargo isn't involved in the #[path] process and so cannot pass the
+        // complete list of features, so for that reason we don't enable checking of
+        // features for std crates.
+        if mode == Mode::Std {
+            rustflags.arg("--check-cfg=cfg(feature,values(any()))");
+        }
+
+        // Add extra cfg not defined in/by rustc
+        //
+        // Note: Although it would seems that "-Zunstable-options" to `rustflags` is useless as
+        // cargo would implicitly add it, it was discover that sometimes bootstrap only use
+        // `rustflags` without `cargo` making it required.
+        rustflags.arg("-Zunstable-options");
+        for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
+            if restricted_mode.is_none() || *restricted_mode == Some(mode) {
+                rustflags.arg(&check_cfg_arg(name, *values));
+            }
+        }
+
+        // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments
+        // to the host invocation here, but rather Cargo should know what flags to pass rustc
+        // itself.
+        if stage == 0 {
+            hostflags.arg("--cfg=bootstrap");
+        }
+        // Cargo doesn't pass RUSTFLAGS to proc_macros:
+        // https://github.com/rust-lang/cargo/issues/4423
+        // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
+        // We also declare that the flag is expected, which we need to do to not
+        // get warnings about it being unexpected.
+        hostflags.arg("-Zunstable-options");
+        hostflags.arg("--check-cfg=cfg(bootstrap)");
+
+        // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
+        // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
+        // #71458.
+        let mut rustdocflags = rustflags.clone();
+        rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
+        if stage == 0 {
+            rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
+        } else {
+            rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
+        }
+
+        if let Ok(s) = env::var("CARGOFLAGS") {
+            cargo.args(s.split_whitespace());
+        }
+
+        match mode {
+            Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
+            Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
+                // Build proc macros both for the host and the target unless proc-macros are not
+                // supported by the target.
+                if target != compiler.host && cmd_kind != Kind::Check {
+                    let error = command(self.rustc(compiler))
+                        .arg("--target")
+                        .arg(target.rustc_target_arg())
+                        .arg("--print=file-names")
+                        .arg("--crate-type=proc-macro")
+                        .arg("-")
+                        .run_capture(self)
+                        .stderr();
+                    let not_supported = error
+                        .lines()
+                        .any(|line| line.contains("unsupported crate type `proc-macro`"));
+                    if !not_supported {
+                        cargo.arg("-Zdual-proc-macros");
+                        rustflags.arg("-Zdual-proc-macros");
+                    }
+                }
+            }
+        }
+
+        // This tells Cargo (and in turn, rustc) to output more complete
+        // dependency information.  Most importantly for bootstrap, this
+        // includes sysroot artifacts, like libstd, which means that we don't
+        // need to track those in bootstrap (an error prone process!). This
+        // feature is currently unstable as there may be some bugs and such, but
+        // it represents a big improvement in bootstrap's reliability on
+        // rebuilds, so we're using it here.
+        //
+        // For some additional context, see #63470 (the PR originally adding
+        // this), as well as #63012 which is the tracking issue for this
+        // feature on the rustc side.
+        cargo.arg("-Zbinary-dep-depinfo");
+        let allow_features = match mode {
+            Mode::ToolBootstrap | Mode::ToolStd => {
+                // Restrict the allowed features so we don't depend on nightly
+                // accidentally.
+                //
+                // binary-dep-depinfo is used by bootstrap itself for all
+                // compilations.
+                //
+                // Lots of tools depend on proc_macro2 and proc-macro-error.
+                // Those have build scripts which assume nightly features are
+                // available if the `rustc` version is "nighty" or "dev". See
+                // bin/rustc.rs for why that is a problem. Instead of labeling
+                // those features for each individual tool that needs them,
+                // just blanket allow them here.
+                //
+                // If this is ever removed, be sure to add something else in
+                // its place to keep the restrictions in place (or make a way
+                // to unset RUSTC_BOOTSTRAP).
+                "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic"
+                    .to_string()
+            }
+            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(),
+        };
+
+        cargo.arg("-j").arg(self.jobs().to_string());
+
+        // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
+        // Force cargo to output binaries with disambiguating hashes in the name
+        let mut metadata = if compiler.stage == 0 {
+            // Treat stage0 like a special channel, whether it's a normal prior-
+            // release rustc or a local rebuild with the same version, so we
+            // never mix these libraries by accident.
+            "bootstrap".to_string()
+        } else {
+            self.config.channel.to_string()
+        };
+        // We want to make sure that none of the dependencies between
+        // std/test/rustc unify with one another. This is done for weird linkage
+        // reasons but the gist of the problem is that if librustc, libtest, and
+        // libstd all depend on libc from crates.io (which they actually do) we
+        // want to make sure they all get distinct versions. Things get really
+        // weird if we try to unify all these dependencies right now, namely
+        // around how many times the library is linked in dynamic libraries and
+        // such. If rustc were a static executable or if we didn't ship dylibs
+        // this wouldn't be a problem, but we do, so it is. This is in general
+        // just here to make sure things build right. If you can remove this and
+        // things still build right, please do!
+        match mode {
+            Mode::Std => metadata.push_str("std"),
+            // When we're building rustc tools, they're built with a search path
+            // that contains things built during the rustc build. For example,
+            // bitflags is built during the rustc build, and is a dependency of
+            // rustdoc as well. We're building rustdoc in a different target
+            // directory, though, which means that Cargo will rebuild the
+            // dependency. When we go on to build rustdoc, we'll look for
+            // bitflags, and find two different copies: one built during the
+            // rustc step and one that we just built. This isn't always a
+            // problem, somehow -- not really clear why -- but we know that this
+            // fixes things.
+            Mode::ToolRustc => metadata.push_str("tool-rustc"),
+            // Same for codegen backends.
+            Mode::Codegen => metadata.push_str("codegen"),
+            _ => {}
+        }
+        cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
+
+        if cmd_kind == Kind::Clippy {
+            rustflags.arg("-Zforce-unstable-if-unmarked");
+        }
+
+        rustflags.arg("-Zmacro-backtrace");
+
+        let want_rustdoc = self.doc_tests != DocTests::No;
+
+        // Clear the output directory if the real rustc we're using has changed;
+        // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
+        //
+        // Avoid doing this during dry run as that usually means the relevant
+        // compiler is not yet linked/copied properly.
+        //
+        // Only clear out the directory if we're compiling std; otherwise, we
+        // should let Cargo take care of things for us (via depdep info)
+        if !self.config.dry_run() && mode == Mode::Std && cmd_kind == Kind::Build {
+            self.clear_if_dirty(&out_dir, &self.rustc(compiler));
+        }
+
+        let rustdoc_path = match cmd_kind {
+            Kind::Doc | Kind::Test | Kind::MiriTest => self.rustdoc(compiler),
+            _ => PathBuf::from("/path/to/nowhere/rustdoc/not/required"),
+        };
+
+        // Customize the compiler we're running. Specify the compiler to cargo
+        // as our shim and then pass it some various options used to configure
+        // how the actual compiler itself is called.
+        //
+        // These variables are primarily all read by
+        // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
+        cargo
+            .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
+            .env("RUSTC_REAL", self.rustc(compiler))
+            .env("RUSTC_STAGE", stage.to_string())
+            .env("RUSTC_SYSROOT", sysroot)
+            .env("RUSTC_LIBDIR", libdir)
+            .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
+            .env("RUSTDOC_REAL", rustdoc_path)
+            .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
+            .env("RUSTC_BREAK_ON_ICE", "1");
+
+        // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
+        // sysroot depending on whether we're building build scripts.
+        // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
+        // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
+        cargo.env("RUSTC_WRAPPER", self.bootstrap_out.join("rustc"));
+        // NOTE: we also need to set RUSTC so cargo can run `rustc -vV`; apparently that ignores RUSTC_WRAPPER >:(
+        cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
+
+        // Someone might have set some previous rustc wrapper (e.g.
+        // sccache) before bootstrap overrode it. Respect that variable.
+        if let Some(existing_wrapper) = env::var_os("RUSTC_WRAPPER") {
+            cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper);
+        }
+
+        // If this is for `miri-test`, prepare the sysroots.
+        if cmd_kind == Kind::MiriTest {
+            self.ensure(compile::Std::new(compiler, compiler.host));
+            let host_sysroot = self.sysroot(compiler);
+            let miri_sysroot = test::Miri::build_miri_sysroot(self, compiler, target);
+            cargo.env("MIRI_SYSROOT", &miri_sysroot);
+            cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
+        }
+
+        cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string());
+
+        if let Some(stack_protector) = &self.config.rust_stack_protector {
+            rustflags.arg(&format!("-Zstack-protector={stack_protector}"));
+        }
+
+        if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc
+        {
+            cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
+        }
+
+        let debuginfo_level = match mode {
+            Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
+            Mode::Std => self.config.rust_debuginfo_level_std,
+            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
+                self.config.rust_debuginfo_level_tools
+            }
+        };
+        cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
+        if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() {
+            cargo.env(profile_var("OPT_LEVEL"), opt_level);
+        }
+        cargo.env(
+            profile_var("DEBUG_ASSERTIONS"),
+            if mode == Mode::Std {
+                self.config.rust_debug_assertions_std.to_string()
+            } else {
+                self.config.rust_debug_assertions.to_string()
+            },
+        );
+        cargo.env(
+            profile_var("OVERFLOW_CHECKS"),
+            if mode == Mode::Std {
+                self.config.rust_overflow_checks_std.to_string()
+            } else {
+                self.config.rust_overflow_checks.to_string()
+            },
+        );
+
+        match self.config.split_debuginfo(target) {
+            SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
+            SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
+            SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
+        };
+
+        if self.config.cmd.bless() {
+            // Bless `expect!` tests.
+            cargo.env("UPDATE_EXPECT", "1");
+        }
+
+        if !mode.is_tool() {
+            cargo.env("RUSTC_FORCE_UNSTABLE", "1");
+        }
+
+        if let Some(x) = self.crt_static(target) {
+            if x {
+                rustflags.arg("-Ctarget-feature=+crt-static");
+            } else {
+                rustflags.arg("-Ctarget-feature=-crt-static");
+            }
+        }
+
+        if let Some(x) = self.crt_static(compiler.host) {
+            let sign = if x { "+" } else { "-" };
+            hostflags.arg(format!("-Ctarget-feature={sign}crt-static"));
+        }
+
+        if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
+            let map = format!("{}={}", self.build.src.display(), map_to);
+            cargo.env("RUSTC_DEBUGINFO_MAP", map);
+
+            // `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
+            // in order to opportunistically reverse it later.
+            cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
+        }
+
+        if self.config.rust_remap_debuginfo {
+            let mut env_var = OsString::new();
+            if self.config.vendor {
+                let vendor = self.build.src.join("vendor");
+                env_var.push(vendor);
+                env_var.push("=/rust/deps");
+            } else {
+                let registry_src = t!(home::cargo_home()).join("registry").join("src");
+                for entry in t!(std::fs::read_dir(registry_src)) {
+                    if !env_var.is_empty() {
+                        env_var.push("\t");
+                    }
+                    env_var.push(t!(entry).path());
+                    env_var.push("=/rust/deps");
+                }
+            }
+            cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var);
+        }
+
+        // Enable usage of unstable features
+        cargo.env("RUSTC_BOOTSTRAP", "1");
+
+        if self.config.dump_bootstrap_shims {
+            prepare_behaviour_dump_dir(self.build);
+
+            cargo
+                .env("DUMP_BOOTSTRAP_SHIMS", self.build.out.join("bootstrap-shims-dump"))
+                .env("BUILD_OUT", &self.build.out)
+                .env("CARGO_HOME", t!(home::cargo_home()));
+        };
+
+        self.add_rust_test_threads(&mut cargo);
+
+        // Almost all of the crates that we compile as part of the bootstrap may
+        // have a build script, including the standard library. To compile a
+        // build script, however, it itself needs a standard library! This
+        // introduces a bit of a pickle when we're compiling the standard
+        // library itself.
+        //
+        // To work around this we actually end up using the snapshot compiler
+        // (stage0) for compiling build scripts of the standard library itself.
+        // The stage0 compiler is guaranteed to have a libstd available for use.
+        //
+        // For other crates, however, we know that we've already got a standard
+        // library up and running, so we can use the normal compiler to compile
+        // build scripts in that situation.
+        if mode == Mode::Std {
+            cargo
+                .env("RUSTC_SNAPSHOT", &self.initial_rustc)
+                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
+        } else {
+            cargo
+                .env("RUSTC_SNAPSHOT", self.rustc(compiler))
+                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
+        }
+
+        // Tools that use compiler libraries may inherit the `-lLLVM` link
+        // requirement, but the `-L` library path is not propagated across
+        // separate Cargo projects. We can add LLVM's library path to the
+        // platform-specific environment variable as a workaround.
+        if mode == Mode::ToolRustc || mode == Mode::Codegen {
+            if let Some(llvm_config) = self.llvm_config(target) {
+                let llvm_libdir =
+                    command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
+                add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
+            }
+        }
+
+        // Compile everything except libraries and proc macros with the more
+        // efficient initial-exec TLS model. This doesn't work with `dlopen`,
+        // so we can't use it by default in general, but we can use it for tools
+        // and our own internal libraries.
+        if !mode.must_support_dlopen() && !target.triple.starts_with("powerpc-") {
+            cargo.env("RUSTC_TLS_MODEL_INITIAL_EXEC", "1");
+        }
+
+        // Ignore incremental modes except for stage0, since we're
+        // not guaranteeing correctness across builds if the compiler
+        // is changing under your feet.
+        if self.config.incremental && compiler.stage == 0 {
+            cargo.env("CARGO_INCREMENTAL", "1");
+        } else {
+            // Don't rely on any default setting for incr. comp. in Cargo
+            cargo.env("CARGO_INCREMENTAL", "0");
+        }
+
+        if let Some(ref on_fail) = self.config.on_fail {
+            cargo.env("RUSTC_ON_FAIL", on_fail);
+        }
+
+        if self.config.print_step_timings {
+            cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
+        }
+
+        if self.config.print_step_rusage {
+            cargo.env("RUSTC_PRINT_STEP_RUSAGE", "1");
+        }
+
+        if self.config.backtrace_on_ice {
+            cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
+        }
+
+        if self.is_verbose() {
+            // This provides very useful logs especially when debugging build cache-related stuff.
+            cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
+        }
+
+        cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
+
+        // Downstream forks of the Rust compiler might want to use a custom libc to add support for
+        // targets that are not yet available upstream. Adding a patch to replace libc with a
+        // custom one would cause compilation errors though, because Cargo would interpret the
+        // custom libc as part of the workspace, and apply the check-cfg lints on it.
+        //
+        // The libc build script emits check-cfg flags only when this environment variable is set,
+        // so this line allows the use of custom libcs.
+        cargo.env("LIBC_CHECK_CFG", "1");
+
+        if source_type == SourceType::InTree {
+            let mut lint_flags = Vec::new();
+            // When extending this list, add the new lints to the RUSTFLAGS of the
+            // build_bootstrap function of src/bootstrap/bootstrap.py as well as
+            // some code doesn't go through this `rustc` wrapper.
+            lint_flags.push("-Wrust_2018_idioms");
+            lint_flags.push("-Wunused_lifetimes");
+
+            if self.config.deny_warnings {
+                lint_flags.push("-Dwarnings");
+                rustdocflags.arg("-Dwarnings");
+            }
+
+            // This does not use RUSTFLAGS due to caching issues with Cargo.
+            // Clippy is treated as an "in tree" tool, but shares the same
+            // cache as other "submodule" tools. With these options set in
+            // RUSTFLAGS, that causes *every* shared dependency to be rebuilt.
+            // By injecting this into the rustc wrapper, this circumvents
+            // Cargo's fingerprint detection. This is fine because lint flags
+            // are always ignored in dependencies. Eventually this should be
+            // fixed via better support from Cargo.
+            cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
+
+            rustdocflags.arg("-Wrustdoc::invalid_codeblock_attributes");
+        }
+
+        if mode == Mode::Rustc {
+            rustflags.arg("-Wrustc::internal");
+            // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all
+            // of the individual lints are satisfied.
+            rustflags.arg("-Wkeyword_idents_2024");
+            rustflags.arg("-Wunsafe_op_in_unsafe_fn");
+        }
+
+        if self.config.rust_frame_pointers {
+            rustflags.arg("-Cforce-frame-pointers=true");
+        }
+
+        // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
+        // when compiling the standard library, since this might be linked into the final outputs
+        // produced by rustc. Since this mitigation is only available on Windows, only enable it
+        // for the standard library in case the compiler is run on a non-Windows platform.
+        // This is not needed for stage 0 artifacts because these will only be used for building
+        // the stage 1 compiler.
+        if cfg!(windows)
+            && mode == Mode::Std
+            && self.config.control_flow_guard
+            && compiler.stage >= 1
+        {
+            rustflags.arg("-Ccontrol-flow-guard");
+        }
+
+        // If EHCont Guard is enabled, pass the `-Zehcont-guard` flag to rustc when compiling the
+        // standard library, since this might be linked into the final outputs produced by rustc.
+        // Since this mitigation is only available on Windows, only enable it for the standard
+        // library in case the compiler is run on a non-Windows platform.
+        // This is not needed for stage 0 artifacts because these will only be used for building
+        // the stage 1 compiler.
+        if cfg!(windows) && mode == Mode::Std && self.config.ehcont_guard && compiler.stage >= 1 {
+            rustflags.arg("-Zehcont-guard");
+        }
+
+        // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
+        // This replaces spaces with tabs because RUSTDOCFLAGS does not
+        // support arguments with regular spaces. Hopefully someday Cargo will
+        // have space support.
+        let rust_version = self.rust_version().replace(' ', "\t");
+        rustdocflags.arg("--crate-version").arg(&rust_version);
+
+        // Environment variables *required* throughout the build
+        //
+        // FIXME: should update code to not require this env var
+
+        // The host this new compiler will *run* on.
+        cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
+        // The host this new compiler is being *built* on.
+        cargo.env("CFG_COMPILER_BUILD_TRIPLE", compiler.host.triple);
+
+        // Set this for all builds to make sure doc builds also get it.
+        cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
+
+        // This one's a bit tricky. As of the time of this writing the compiler
+        // links to the `winapi` crate on crates.io. This crate provides raw
+        // bindings to Windows system functions, sort of like libc does for
+        // Unix. This crate also, however, provides "import libraries" for the
+        // MinGW targets. There's an import library per dll in the windows
+        // distribution which is what's linked to. These custom import libraries
+        // are used because the winapi crate can reference Windows functions not
+        // present in the MinGW import libraries.
+        //
+        // For example MinGW may ship libdbghelp.a, but it may not have
+        // references to all the functions in the dbghelp dll. Instead the
+        // custom import library for dbghelp in the winapi crates has all this
+        // information.
+        //
+        // Unfortunately for us though the import libraries are linked by
+        // default via `-ldylib=winapi_foo`. That is, they're linked with the
+        // `dylib` type with a `winapi_` prefix (so the winapi ones don't
+        // conflict with the system MinGW ones). This consequently means that
+        // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
+        // DLL) when linked against *again*, for example with procedural macros
+        // or plugins, will trigger the propagation logic of `-ldylib`, passing
+        // `-lwinapi_foo` to the linker again. This isn't actually available in
+        // our distribution, however, so the link fails.
+        //
+        // To solve this problem we tell winapi to not use its bundled import
+        // libraries. This means that it will link to the system MinGW import
+        // libraries by default, and the `-ldylib=foo` directives will still get
+        // passed to the final linker, but they'll look like `-lfoo` which can
+        // be resolved because MinGW has the import library. The downside is we
+        // don't get newer functions from Windows, but we don't use any of them
+        // anyway.
+        if !mode.is_tool() {
+            cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
+        }
+
+        for _ in 0..self.verbosity {
+            cargo.arg("-v");
+        }
+
+        match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) {
+            (Mode::Std, Some(n), _) | (_, _, Some(n)) => {
+                cargo.env(profile_var("CODEGEN_UNITS"), n.to_string());
+            }
+            _ => {
+                // Don't set anything
+            }
+        }
+
+        if self.config.locked_deps {
+            cargo.arg("--locked");
+        }
+        if self.config.vendor || self.is_sudo {
+            cargo.arg("--frozen");
+        }
+
+        // Try to use a sysroot-relative bindir, in case it was configured absolutely.
+        cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
+
+        cargo.force_coloring_in_ci();
+
+        // When we build Rust dylibs they're all intended for intermediate
+        // usage, so make sure we pass the -Cprefer-dynamic flag instead of
+        // linking all deps statically into the dylib.
+        if matches!(mode, Mode::Std) {
+            rustflags.arg("-Cprefer-dynamic");
+        }
+        if matches!(mode, Mode::Rustc) && !self.link_std_into_rustc_driver(target) {
+            rustflags.arg("-Cprefer-dynamic");
+        }
+
+        cargo.env(
+            "RUSTC_LINK_STD_INTO_RUSTC_DRIVER",
+            if self.link_std_into_rustc_driver(target) { "1" } else { "0" },
+        );
+
+        // When building incrementally we default to a lower ThinLTO import limit
+        // (unless explicitly specified otherwise). This will produce a somewhat
+        // slower code but give way better compile times.
+        {
+            let limit = match self.config.rust_thin_lto_import_instr_limit {
+                Some(limit) => Some(limit),
+                None if self.config.incremental => Some(10),
+                _ => None,
+            };
+
+            if let Some(limit) = limit {
+                if stage == 0
+                    || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm"
+                {
+                    rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
+                }
+            }
+        }
+
+        if matches!(mode, Mode::Std) {
+            if let Some(mir_opt_level) = self.config.rust_validate_mir_opts {
+                rustflags.arg("-Zvalidate-mir");
+                rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}"));
+            }
+            if self.config.rust_randomize_layout {
+                rustflags.arg("--cfg=randomized_layouts");
+            }
+            // Always enable inlining MIR when building the standard library.
+            // Without this flag, MIR inlining is disabled when incremental compilation is enabled.
+            // That causes some mir-opt tests which inline functions from the standard library to
+            // break when incremental compilation is enabled. So this overrides the "no inlining
+            // during incremental builds" heuristic for the standard library.
+            rustflags.arg("-Zinline-mir");
+
+            // Similarly, we need to keep debug info for functions inlined into other std functions,
+            // even if we're not going to output debuginfo for the crate we're currently building,
+            // so that it'll be available when downstream consumers of std try to use it.
+            rustflags.arg("-Zinline-mir-preserve-debug");
+        }
+
+        if self.config.rustc_parallel
+            && matches!(mode, Mode::ToolRustc | Mode::Rustc | Mode::Codegen)
+        {
+            // keep in sync with `bootstrap/lib.rs:Build::rustc_features`
+            // `cfg` option for rustc, `features` option for cargo, for conditional compilation
+            rustflags.arg("--cfg=parallel_compiler");
+            rustdocflags.arg("--cfg=parallel_compiler");
+        }
+
+        Cargo {
+            command: cargo,
+            compiler,
+            target,
+            rustflags,
+            rustdocflags,
+            hostflags,
+            allow_features,
+        }
+    }
+}
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder/mod.rs
index 8cea01434fe..8f8ab112857 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1,7 +1,8 @@
+mod cargo;
+
 use std::any::{Any, type_name};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
-use std::ffi::{OsStr, OsString};
 use std::fmt::{Debug, Write};
 use std::hash::Hash;
 use std::ops::Deref;
@@ -12,22 +13,17 @@ use std::{env, fs};
 
 use clap::ValueEnum;
 
+pub use self::cargo::Cargo;
 pub use crate::Compiler;
-use crate::core::build_steps::tool::{self, SourceType};
 use crate::core::build_steps::{
-    check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, vendor,
+    check, clean, clippy, compile, dist, doc, gcc, install, llvm, run, setup, test, tool, vendor,
 };
-use crate::core::config::flags::{Color, Subcommand};
-use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection};
+use crate::core::config::flags::Subcommand;
+use crate::core::config::{DryRun, TargetSelection};
 use crate::utils::cache::Cache;
 use crate::utils::exec::{BootstrapCommand, command};
-use crate::utils::helpers::{
-    self, LldThreads, add_dylib_path, add_link_lib_path, check_cfg_arg, exe, libdir, linker_args,
-    linker_flags, t,
-};
-use crate::{
-    Build, CLang, Crate, DocTests, EXTRA_CHECK_CFGS, GitRepo, Mode, prepare_behaviour_dump_dir,
-};
+use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t};
+use crate::{Build, Crate};
 
 #[cfg(test)]
 mod tests;
@@ -1410,870 +1406,6 @@ impl<'a> Builder<'a> {
         None
     }
 
-    /// Like `cargo`, but only passes flags that are valid for all commands.
-    pub fn bare_cargo(
-        &self,
-        compiler: Compiler,
-        mode: Mode,
-        target: TargetSelection,
-        cmd_kind: Kind,
-    ) -> BootstrapCommand {
-        let mut cargo = match cmd_kind {
-            Kind::Clippy => {
-                let mut cargo = self.cargo_clippy_cmd(compiler);
-                cargo.arg(cmd_kind.as_str());
-                cargo
-            }
-            Kind::MiriSetup => {
-                let mut cargo = self.cargo_miri_cmd(compiler);
-                cargo.arg("miri").arg("setup");
-                cargo
-            }
-            Kind::MiriTest => {
-                let mut cargo = self.cargo_miri_cmd(compiler);
-                cargo.arg("miri").arg("test");
-                cargo
-            }
-            _ => {
-                let mut cargo = command(&self.initial_cargo);
-                cargo.arg(cmd_kind.as_str());
-                cargo
-            }
-        };
-
-        // Run cargo from the source root so it can find .cargo/config.
-        // This matters when using vendoring and the working directory is outside the repository.
-        cargo.current_dir(&self.src);
-
-        let out_dir = self.stage_out(compiler, mode);
-        cargo.env("CARGO_TARGET_DIR", &out_dir);
-
-        // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger`
-        // from out of tree it shouldn't matter, since x.py is only used for
-        // building in-tree.
-        let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"];
-        match self.build.config.color {
-            Color::Always => {
-                cargo.arg("--color=always");
-                for log in &color_logs {
-                    cargo.env(log, "always");
-                }
-            }
-            Color::Never => {
-                cargo.arg("--color=never");
-                for log in &color_logs {
-                    cargo.env(log, "never");
-                }
-            }
-            Color::Auto => {} // nothing to do
-        }
-
-        if cmd_kind != Kind::Install {
-            cargo.arg("--target").arg(target.rustc_target_arg());
-        } else {
-            assert_eq!(target, compiler.host);
-        }
-
-        if self.config.rust_optimize.is_release() &&
-        // cargo bench/install do not accept `--release` and miri doesn't want it
-        !matches!(cmd_kind, Kind::Bench | Kind::Install | Kind::Miri | Kind::MiriSetup | Kind::MiriTest)
-        {
-            cargo.arg("--release");
-        }
-
-        // Remove make-related flags to ensure Cargo can correctly set things up
-        cargo.env_remove("MAKEFLAGS");
-        cargo.env_remove("MFLAGS");
-
-        cargo
-    }
-
-    /// This will create a `Command` that represents a pending execution of
-    /// Cargo. This cargo will be configured to use `compiler` as the actual
-    /// rustc compiler, its output will be scoped by `mode`'s output directory,
-    /// it will pass the `--target` flag for the specified `target`, and will be
-    /// executing the Cargo command `cmd`. `cmd` can be `miri-cmd` for commands
-    /// to be run with Miri.
-    fn cargo(
-        &self,
-        compiler: Compiler,
-        mode: Mode,
-        source_type: SourceType,
-        target: TargetSelection,
-        cmd_kind: Kind,
-    ) -> Cargo {
-        let mut cargo = self.bare_cargo(compiler, mode, target, cmd_kind);
-        let out_dir = self.stage_out(compiler, mode);
-
-        let mut hostflags = HostFlags::default();
-
-        // Codegen backends are not yet tracked by -Zbinary-dep-depinfo,
-        // so we need to explicitly clear out if they've been updated.
-        for backend in self.codegen_backends(compiler) {
-            self.clear_if_dirty(&out_dir, &backend);
-        }
-
-        if cmd_kind == Kind::Doc {
-            let my_out = match mode {
-                // This is the intended out directory for compiler documentation.
-                Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target),
-                Mode::Std => {
-                    if self.config.cmd.json() {
-                        out_dir.join(target).join("json-doc")
-                    } else {
-                        out_dir.join(target).join("doc")
-                    }
-                }
-                _ => panic!("doc mode {mode:?} not expected"),
-            };
-            let rustdoc = self.rustdoc(compiler);
-            self.clear_if_dirty(&my_out, &rustdoc);
-        }
-
-        let profile_var = |name: &str| {
-            let profile = if self.config.rust_optimize.is_release() { "RELEASE" } else { "DEV" };
-            format!("CARGO_PROFILE_{}_{}", profile, name)
-        };
-
-        // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config
-        // needs to not accidentally link to libLLVM in stage0/lib.
-        cargo.env("REAL_LIBRARY_PATH_VAR", helpers::dylib_path_var());
-        if let Some(e) = env::var_os(helpers::dylib_path_var()) {
-            cargo.env("REAL_LIBRARY_PATH", e);
-        }
-
-        // Set a flag for `check`/`clippy`/`fix`, so that certain build
-        // scripts can do less work (i.e. not building/requiring LLVM).
-        if matches!(cmd_kind, Kind::Check | Kind::Clippy | Kind::Fix) {
-            // If we've not yet built LLVM, or it's stale, then bust
-            // the rustc_llvm cache. That will always work, even though it
-            // may mean that on the next non-check build we'll need to rebuild
-            // rustc_llvm. But if LLVM is stale, that'll be a tiny amount
-            // of work comparatively, and we'd likely need to rebuild it anyway,
-            // so that's okay.
-            if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target, false)
-                .should_build()
-            {
-                cargo.env("RUST_CHECK", "1");
-            }
-        }
-
-        let stage = if compiler.stage == 0 && self.local_rebuild {
-            // Assume the local-rebuild rustc already has stage1 features.
-            1
-        } else {
-            compiler.stage
-        };
-
-        // We synthetically interpret a stage0 compiler used to build tools as a
-        // "raw" compiler in that it's the exact snapshot we download. Normally
-        // the stage0 build means it uses libraries build by the stage0
-        // compiler, but for tools we just use the precompiled libraries that
-        // we've downloaded
-        let use_snapshot = mode == Mode::ToolBootstrap;
-        assert!(!use_snapshot || stage == 0 || self.local_rebuild);
-
-        let maybe_sysroot = self.sysroot(compiler);
-        let sysroot = if use_snapshot { self.rustc_snapshot_sysroot() } else { &maybe_sysroot };
-        let libdir = self.rustc_libdir(compiler);
-
-        let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
-        if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
-            println!("using sysroot {sysroot_str}");
-        }
-
-        let mut rustflags = Rustflags::new(target);
-        if stage != 0 {
-            if let Ok(s) = env::var("CARGOFLAGS_NOT_BOOTSTRAP") {
-                cargo.args(s.split_whitespace());
-            }
-            rustflags.env("RUSTFLAGS_NOT_BOOTSTRAP");
-        } else {
-            if let Ok(s) = env::var("CARGOFLAGS_BOOTSTRAP") {
-                cargo.args(s.split_whitespace());
-            }
-            rustflags.env("RUSTFLAGS_BOOTSTRAP");
-            rustflags.arg("--cfg=bootstrap");
-        }
-
-        if cmd_kind == Kind::Clippy {
-            // clippy overwrites sysroot if we pass it to cargo.
-            // Pass it directly to clippy instead.
-            // NOTE: this can't be fixed in clippy because we explicitly don't set `RUSTC`,
-            // so it has no way of knowing the sysroot.
-            rustflags.arg("--sysroot");
-            rustflags.arg(sysroot_str);
-        }
-
-        let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling {
-            Some(setting) => {
-                // If an explicit setting is given, use that
-                setting
-            }
-            None => {
-                if mode == Mode::Std {
-                    // The standard library defaults to the legacy scheme
-                    false
-                } else {
-                    // The compiler and tools default to the new scheme
-                    true
-                }
-            }
-        };
-
-        // By default, windows-rs depends on a native library that doesn't get copied into the
-        // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native
-        // library unnecessary. This can be removed when windows-rs enables raw-dylib
-        // unconditionally.
-        if let Mode::Rustc | Mode::ToolRustc = mode {
-            rustflags.arg("--cfg=windows_raw_dylib");
-        }
-
-        if use_new_symbol_mangling {
-            rustflags.arg("-Csymbol-mangling-version=v0");
-        } else {
-            rustflags.arg("-Csymbol-mangling-version=legacy");
-        }
-
-        // FIXME: the following components don't build with `-Zrandomize-layout` yet:
-        // - wasm-component-ld, due to the `wast`crate
-        // - rust-analyzer, due to the rowan crate
-        // so we exclude entire categories of steps here due to lack of fine-grained control over
-        // rustflags.
-        if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc {
-            rustflags.arg("-Zrandomize-layout");
-        }
-
-        // Enable compile-time checking of `cfg` names, values and Cargo `features`.
-        //
-        // Note: `std`, `alloc` and `core` imports some dependencies by #[path] (like
-        // backtrace, core_simd, std_float, ...), those dependencies have their own
-        // features but cargo isn't involved in the #[path] process and so cannot pass the
-        // complete list of features, so for that reason we don't enable checking of
-        // features for std crates.
-        if mode == Mode::Std {
-            rustflags.arg("--check-cfg=cfg(feature,values(any()))");
-        }
-
-        // Add extra cfg not defined in/by rustc
-        //
-        // Note: Although it would seems that "-Zunstable-options" to `rustflags` is useless as
-        // cargo would implicitly add it, it was discover that sometimes bootstrap only use
-        // `rustflags` without `cargo` making it required.
-        rustflags.arg("-Zunstable-options");
-        for (restricted_mode, name, values) in EXTRA_CHECK_CFGS {
-            if restricted_mode.is_none() || *restricted_mode == Some(mode) {
-                rustflags.arg(&check_cfg_arg(name, *values));
-            }
-        }
-
-        // FIXME(rust-lang/cargo#5754) we shouldn't be using special command arguments
-        // to the host invocation here, but rather Cargo should know what flags to pass rustc
-        // itself.
-        if stage == 0 {
-            hostflags.arg("--cfg=bootstrap");
-        }
-        // Cargo doesn't pass RUSTFLAGS to proc_macros:
-        // https://github.com/rust-lang/cargo/issues/4423
-        // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
-        // We also declare that the flag is expected, which we need to do to not
-        // get warnings about it being unexpected.
-        hostflags.arg("-Zunstable-options");
-        hostflags.arg("--check-cfg=cfg(bootstrap)");
-
-        // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
-        // but this breaks CI. At the very least, stage0 `rustdoc` needs `--cfg bootstrap`. See
-        // #71458.
-        let mut rustdocflags = rustflags.clone();
-        rustdocflags.propagate_cargo_env("RUSTDOCFLAGS");
-        if stage == 0 {
-            rustdocflags.env("RUSTDOCFLAGS_BOOTSTRAP");
-        } else {
-            rustdocflags.env("RUSTDOCFLAGS_NOT_BOOTSTRAP");
-        }
-
-        if let Ok(s) = env::var("CARGOFLAGS") {
-            cargo.args(s.split_whitespace());
-        }
-
-        match mode {
-            Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {}
-            Mode::Rustc | Mode::Codegen | Mode::ToolRustc => {
-                // Build proc macros both for the host and the target unless proc-macros are not
-                // supported by the target.
-                if target != compiler.host && cmd_kind != Kind::Check {
-                    let error = command(self.rustc(compiler))
-                        .arg("--target")
-                        .arg(target.rustc_target_arg())
-                        .arg("--print=file-names")
-                        .arg("--crate-type=proc-macro")
-                        .arg("-")
-                        .run_capture(self)
-                        .stderr();
-                    let not_supported = error
-                        .lines()
-                        .any(|line| line.contains("unsupported crate type `proc-macro`"));
-                    if !not_supported {
-                        cargo.arg("-Zdual-proc-macros");
-                        rustflags.arg("-Zdual-proc-macros");
-                    }
-                }
-            }
-        }
-
-        // This tells Cargo (and in turn, rustc) to output more complete
-        // dependency information.  Most importantly for bootstrap, this
-        // includes sysroot artifacts, like libstd, which means that we don't
-        // need to track those in bootstrap (an error prone process!). This
-        // feature is currently unstable as there may be some bugs and such, but
-        // it represents a big improvement in bootstrap's reliability on
-        // rebuilds, so we're using it here.
-        //
-        // For some additional context, see #63470 (the PR originally adding
-        // this), as well as #63012 which is the tracking issue for this
-        // feature on the rustc side.
-        cargo.arg("-Zbinary-dep-depinfo");
-        let allow_features = match mode {
-            Mode::ToolBootstrap | Mode::ToolStd => {
-                // Restrict the allowed features so we don't depend on nightly
-                // accidentally.
-                //
-                // binary-dep-depinfo is used by bootstrap itself for all
-                // compilations.
-                //
-                // Lots of tools depend on proc_macro2 and proc-macro-error.
-                // Those have build scripts which assume nightly features are
-                // available if the `rustc` version is "nighty" or "dev". See
-                // bin/rustc.rs for why that is a problem. Instead of labeling
-                // those features for each individual tool that needs them,
-                // just blanket allow them here.
-                //
-                // If this is ever removed, be sure to add something else in
-                // its place to keep the restrictions in place (or make a way
-                // to unset RUSTC_BOOTSTRAP).
-                "binary-dep-depinfo,proc_macro_span,proc_macro_span_shrink,proc_macro_diagnostic"
-                    .to_string()
-            }
-            Mode::Std | Mode::Rustc | Mode::Codegen | Mode::ToolRustc => String::new(),
-        };
-
-        cargo.arg("-j").arg(self.jobs().to_string());
-
-        // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005
-        // Force cargo to output binaries with disambiguating hashes in the name
-        let mut metadata = if compiler.stage == 0 {
-            // Treat stage0 like a special channel, whether it's a normal prior-
-            // release rustc or a local rebuild with the same version, so we
-            // never mix these libraries by accident.
-            "bootstrap".to_string()
-        } else {
-            self.config.channel.to_string()
-        };
-        // We want to make sure that none of the dependencies between
-        // std/test/rustc unify with one another. This is done for weird linkage
-        // reasons but the gist of the problem is that if librustc, libtest, and
-        // libstd all depend on libc from crates.io (which they actually do) we
-        // want to make sure they all get distinct versions. Things get really
-        // weird if we try to unify all these dependencies right now, namely
-        // around how many times the library is linked in dynamic libraries and
-        // such. If rustc were a static executable or if we didn't ship dylibs
-        // this wouldn't be a problem, but we do, so it is. This is in general
-        // just here to make sure things build right. If you can remove this and
-        // things still build right, please do!
-        match mode {
-            Mode::Std => metadata.push_str("std"),
-            // When we're building rustc tools, they're built with a search path
-            // that contains things built during the rustc build. For example,
-            // bitflags is built during the rustc build, and is a dependency of
-            // rustdoc as well. We're building rustdoc in a different target
-            // directory, though, which means that Cargo will rebuild the
-            // dependency. When we go on to build rustdoc, we'll look for
-            // bitflags, and find two different copies: one built during the
-            // rustc step and one that we just built. This isn't always a
-            // problem, somehow -- not really clear why -- but we know that this
-            // fixes things.
-            Mode::ToolRustc => metadata.push_str("tool-rustc"),
-            // Same for codegen backends.
-            Mode::Codegen => metadata.push_str("codegen"),
-            _ => {}
-        }
-        cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata);
-
-        if cmd_kind == Kind::Clippy {
-            rustflags.arg("-Zforce-unstable-if-unmarked");
-        }
-
-        rustflags.arg("-Zmacro-backtrace");
-
-        let want_rustdoc = self.doc_tests != DocTests::No;
-
-        // Clear the output directory if the real rustc we're using has changed;
-        // Cargo cannot detect this as it thinks rustc is bootstrap/debug/rustc.
-        //
-        // Avoid doing this during dry run as that usually means the relevant
-        // compiler is not yet linked/copied properly.
-        //
-        // Only clear out the directory if we're compiling std; otherwise, we
-        // should let Cargo take care of things for us (via depdep info)
-        if !self.config.dry_run() && mode == Mode::Std && cmd_kind == Kind::Build {
-            self.clear_if_dirty(&out_dir, &self.rustc(compiler));
-        }
-
-        let rustdoc_path = match cmd_kind {
-            Kind::Doc | Kind::Test | Kind::MiriTest => self.rustdoc(compiler),
-            _ => PathBuf::from("/path/to/nowhere/rustdoc/not/required"),
-        };
-
-        // Customize the compiler we're running. Specify the compiler to cargo
-        // as our shim and then pass it some various options used to configure
-        // how the actual compiler itself is called.
-        //
-        // These variables are primarily all read by
-        // src/bootstrap/bin/{rustc.rs,rustdoc.rs}
-        cargo
-            .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target))
-            .env("RUSTC_REAL", self.rustc(compiler))
-            .env("RUSTC_STAGE", stage.to_string())
-            .env("RUSTC_SYSROOT", sysroot)
-            .env("RUSTC_LIBDIR", libdir)
-            .env("RUSTDOC", self.bootstrap_out.join("rustdoc"))
-            .env("RUSTDOC_REAL", rustdoc_path)
-            .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir())
-            .env("RUSTC_BREAK_ON_ICE", "1");
-
-        // Set RUSTC_WRAPPER to the bootstrap shim, which switches between beta and in-tree
-        // sysroot depending on whether we're building build scripts.
-        // NOTE: we intentionally use RUSTC_WRAPPER so that we can support clippy - RUSTC is not
-        // respected by clippy-driver; RUSTC_WRAPPER happens earlier, before clippy runs.
-        cargo.env("RUSTC_WRAPPER", self.bootstrap_out.join("rustc"));
-        // NOTE: we also need to set RUSTC so cargo can run `rustc -vV`; apparently that ignores RUSTC_WRAPPER >:(
-        cargo.env("RUSTC", self.bootstrap_out.join("rustc"));
-
-        // Someone might have set some previous rustc wrapper (e.g.
-        // sccache) before bootstrap overrode it. Respect that variable.
-        if let Some(existing_wrapper) = env::var_os("RUSTC_WRAPPER") {
-            cargo.env("RUSTC_WRAPPER_REAL", existing_wrapper);
-        }
-
-        // If this is for `miri-test`, prepare the sysroots.
-        if cmd_kind == Kind::MiriTest {
-            self.ensure(compile::Std::new(compiler, compiler.host));
-            let host_sysroot = self.sysroot(compiler);
-            let miri_sysroot = test::Miri::build_miri_sysroot(self, compiler, target);
-            cargo.env("MIRI_SYSROOT", &miri_sysroot);
-            cargo.env("MIRI_HOST_SYSROOT", &host_sysroot);
-        }
-
-        cargo.env(profile_var("STRIP"), self.config.rust_strip.to_string());
-
-        if let Some(stack_protector) = &self.config.rust_stack_protector {
-            rustflags.arg(&format!("-Zstack-protector={stack_protector}"));
-        }
-
-        if !matches!(cmd_kind, Kind::Build | Kind::Check | Kind::Clippy | Kind::Fix) && want_rustdoc
-        {
-            cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(compiler));
-        }
-
-        let debuginfo_level = match mode {
-            Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc,
-            Mode::Std => self.config.rust_debuginfo_level_std,
-            Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => {
-                self.config.rust_debuginfo_level_tools
-            }
-        };
-        cargo.env(profile_var("DEBUG"), debuginfo_level.to_string());
-        if let Some(opt_level) = &self.config.rust_optimize.get_opt_level() {
-            cargo.env(profile_var("OPT_LEVEL"), opt_level);
-        }
-        cargo.env(
-            profile_var("DEBUG_ASSERTIONS"),
-            if mode == Mode::Std {
-                self.config.rust_debug_assertions_std.to_string()
-            } else {
-                self.config.rust_debug_assertions.to_string()
-            },
-        );
-        cargo.env(
-            profile_var("OVERFLOW_CHECKS"),
-            if mode == Mode::Std {
-                self.config.rust_overflow_checks_std.to_string()
-            } else {
-                self.config.rust_overflow_checks.to_string()
-            },
-        );
-
-        match self.config.split_debuginfo(target) {
-            SplitDebuginfo::Packed => rustflags.arg("-Csplit-debuginfo=packed"),
-            SplitDebuginfo::Unpacked => rustflags.arg("-Csplit-debuginfo=unpacked"),
-            SplitDebuginfo::Off => rustflags.arg("-Csplit-debuginfo=off"),
-        };
-
-        if self.config.cmd.bless() {
-            // Bless `expect!` tests.
-            cargo.env("UPDATE_EXPECT", "1");
-        }
-
-        if !mode.is_tool() {
-            cargo.env("RUSTC_FORCE_UNSTABLE", "1");
-        }
-
-        if let Some(x) = self.crt_static(target) {
-            if x {
-                rustflags.arg("-Ctarget-feature=+crt-static");
-            } else {
-                rustflags.arg("-Ctarget-feature=-crt-static");
-            }
-        }
-
-        if let Some(x) = self.crt_static(compiler.host) {
-            let sign = if x { "+" } else { "-" };
-            hostflags.arg(format!("-Ctarget-feature={sign}crt-static"));
-        }
-
-        if let Some(map_to) = self.build.debuginfo_map_to(GitRepo::Rustc) {
-            let map = format!("{}={}", self.build.src.display(), map_to);
-            cargo.env("RUSTC_DEBUGINFO_MAP", map);
-
-            // `rustc` needs to know the virtual `/rustc/$hash` we're mapping to,
-            // in order to opportunistically reverse it later.
-            cargo.env("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR", map_to);
-        }
-
-        if self.config.rust_remap_debuginfo {
-            let mut env_var = OsString::new();
-            if self.config.vendor {
-                let vendor = self.build.src.join("vendor");
-                env_var.push(vendor);
-                env_var.push("=/rust/deps");
-            } else {
-                let registry_src = t!(home::cargo_home()).join("registry").join("src");
-                for entry in t!(std::fs::read_dir(registry_src)) {
-                    if !env_var.is_empty() {
-                        env_var.push("\t");
-                    }
-                    env_var.push(t!(entry).path());
-                    env_var.push("=/rust/deps");
-                }
-            }
-            cargo.env("RUSTC_CARGO_REGISTRY_SRC_TO_REMAP", env_var);
-        }
-
-        // Enable usage of unstable features
-        cargo.env("RUSTC_BOOTSTRAP", "1");
-
-        if self.config.dump_bootstrap_shims {
-            prepare_behaviour_dump_dir(self.build);
-
-            cargo
-                .env("DUMP_BOOTSTRAP_SHIMS", self.build.out.join("bootstrap-shims-dump"))
-                .env("BUILD_OUT", &self.build.out)
-                .env("CARGO_HOME", t!(home::cargo_home()));
-        };
-
-        self.add_rust_test_threads(&mut cargo);
-
-        // Almost all of the crates that we compile as part of the bootstrap may
-        // have a build script, including the standard library. To compile a
-        // build script, however, it itself needs a standard library! This
-        // introduces a bit of a pickle when we're compiling the standard
-        // library itself.
-        //
-        // To work around this we actually end up using the snapshot compiler
-        // (stage0) for compiling build scripts of the standard library itself.
-        // The stage0 compiler is guaranteed to have a libstd available for use.
-        //
-        // For other crates, however, we know that we've already got a standard
-        // library up and running, so we can use the normal compiler to compile
-        // build scripts in that situation.
-        if mode == Mode::Std {
-            cargo
-                .env("RUSTC_SNAPSHOT", &self.initial_rustc)
-                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir());
-        } else {
-            cargo
-                .env("RUSTC_SNAPSHOT", self.rustc(compiler))
-                .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler));
-        }
-
-        // Tools that use compiler libraries may inherit the `-lLLVM` link
-        // requirement, but the `-L` library path is not propagated across
-        // separate Cargo projects. We can add LLVM's library path to the
-        // platform-specific environment variable as a workaround.
-        if mode == Mode::ToolRustc || mode == Mode::Codegen {
-            if let Some(llvm_config) = self.llvm_config(target) {
-                let llvm_libdir =
-                    command(llvm_config).arg("--libdir").run_capture_stdout(self).stdout();
-                add_link_lib_path(vec![llvm_libdir.trim().into()], &mut cargo);
-            }
-        }
-
-        // Compile everything except libraries and proc macros with the more
-        // efficient initial-exec TLS model. This doesn't work with `dlopen`,
-        // so we can't use it by default in general, but we can use it for tools
-        // and our own internal libraries.
-        if !mode.must_support_dlopen() && !target.triple.starts_with("powerpc-") {
-            cargo.env("RUSTC_TLS_MODEL_INITIAL_EXEC", "1");
-        }
-
-        // Ignore incremental modes except for stage0, since we're
-        // not guaranteeing correctness across builds if the compiler
-        // is changing under your feet.
-        if self.config.incremental && compiler.stage == 0 {
-            cargo.env("CARGO_INCREMENTAL", "1");
-        } else {
-            // Don't rely on any default setting for incr. comp. in Cargo
-            cargo.env("CARGO_INCREMENTAL", "0");
-        }
-
-        if let Some(ref on_fail) = self.config.on_fail {
-            cargo.env("RUSTC_ON_FAIL", on_fail);
-        }
-
-        if self.config.print_step_timings {
-            cargo.env("RUSTC_PRINT_STEP_TIMINGS", "1");
-        }
-
-        if self.config.print_step_rusage {
-            cargo.env("RUSTC_PRINT_STEP_RUSAGE", "1");
-        }
-
-        if self.config.backtrace_on_ice {
-            cargo.env("RUSTC_BACKTRACE_ON_ICE", "1");
-        }
-
-        if self.is_verbose() {
-            // This provides very useful logs especially when debugging build cache-related stuff.
-            cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info");
-        }
-
-        cargo.env("RUSTC_VERBOSE", self.verbosity.to_string());
-
-        // Downstream forks of the Rust compiler might want to use a custom libc to add support for
-        // targets that are not yet available upstream. Adding a patch to replace libc with a
-        // custom one would cause compilation errors though, because Cargo would interpret the
-        // custom libc as part of the workspace, and apply the check-cfg lints on it.
-        //
-        // The libc build script emits check-cfg flags only when this environment variable is set,
-        // so this line allows the use of custom libcs.
-        cargo.env("LIBC_CHECK_CFG", "1");
-
-        if source_type == SourceType::InTree {
-            let mut lint_flags = Vec::new();
-            // When extending this list, add the new lints to the RUSTFLAGS of the
-            // build_bootstrap function of src/bootstrap/bootstrap.py as well as
-            // some code doesn't go through this `rustc` wrapper.
-            lint_flags.push("-Wrust_2018_idioms");
-            lint_flags.push("-Wunused_lifetimes");
-
-            if self.config.deny_warnings {
-                lint_flags.push("-Dwarnings");
-                rustdocflags.arg("-Dwarnings");
-            }
-
-            // This does not use RUSTFLAGS due to caching issues with Cargo.
-            // Clippy is treated as an "in tree" tool, but shares the same
-            // cache as other "submodule" tools. With these options set in
-            // RUSTFLAGS, that causes *every* shared dependency to be rebuilt.
-            // By injecting this into the rustc wrapper, this circumvents
-            // Cargo's fingerprint detection. This is fine because lint flags
-            // are always ignored in dependencies. Eventually this should be
-            // fixed via better support from Cargo.
-            cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" "));
-
-            rustdocflags.arg("-Wrustdoc::invalid_codeblock_attributes");
-        }
-
-        if mode == Mode::Rustc {
-            rustflags.arg("-Wrustc::internal");
-            // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all
-            // of the individual lints are satisfied.
-            rustflags.arg("-Wkeyword_idents_2024");
-            rustflags.arg("-Wunsafe_op_in_unsafe_fn");
-        }
-
-        if self.config.rust_frame_pointers {
-            rustflags.arg("-Cforce-frame-pointers=true");
-        }
-
-        // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
-        // when compiling the standard library, since this might be linked into the final outputs
-        // produced by rustc. Since this mitigation is only available on Windows, only enable it
-        // for the standard library in case the compiler is run on a non-Windows platform.
-        // This is not needed for stage 0 artifacts because these will only be used for building
-        // the stage 1 compiler.
-        if cfg!(windows)
-            && mode == Mode::Std
-            && self.config.control_flow_guard
-            && compiler.stage >= 1
-        {
-            rustflags.arg("-Ccontrol-flow-guard");
-        }
-
-        // If EHCont Guard is enabled, pass the `-Zehcont-guard` flag to rustc when compiling the
-        // standard library, since this might be linked into the final outputs produced by rustc.
-        // Since this mitigation is only available on Windows, only enable it for the standard
-        // library in case the compiler is run on a non-Windows platform.
-        // This is not needed for stage 0 artifacts because these will only be used for building
-        // the stage 1 compiler.
-        if cfg!(windows) && mode == Mode::Std && self.config.ehcont_guard && compiler.stage >= 1 {
-            rustflags.arg("-Zehcont-guard");
-        }
-
-        // For `cargo doc` invocations, make rustdoc print the Rust version into the docs
-        // This replaces spaces with tabs because RUSTDOCFLAGS does not
-        // support arguments with regular spaces. Hopefully someday Cargo will
-        // have space support.
-        let rust_version = self.rust_version().replace(' ', "\t");
-        rustdocflags.arg("--crate-version").arg(&rust_version);
-
-        // Environment variables *required* throughout the build
-        //
-        // FIXME: should update code to not require this env var
-
-        // The host this new compiler will *run* on.
-        cargo.env("CFG_COMPILER_HOST_TRIPLE", target.triple);
-        // The host this new compiler is being *built* on.
-        cargo.env("CFG_COMPILER_BUILD_TRIPLE", compiler.host.triple);
-
-        // Set this for all builds to make sure doc builds also get it.
-        cargo.env("CFG_RELEASE_CHANNEL", &self.config.channel);
-
-        // This one's a bit tricky. As of the time of this writing the compiler
-        // links to the `winapi` crate on crates.io. This crate provides raw
-        // bindings to Windows system functions, sort of like libc does for
-        // Unix. This crate also, however, provides "import libraries" for the
-        // MinGW targets. There's an import library per dll in the windows
-        // distribution which is what's linked to. These custom import libraries
-        // are used because the winapi crate can reference Windows functions not
-        // present in the MinGW import libraries.
-        //
-        // For example MinGW may ship libdbghelp.a, but it may not have
-        // references to all the functions in the dbghelp dll. Instead the
-        // custom import library for dbghelp in the winapi crates has all this
-        // information.
-        //
-        // Unfortunately for us though the import libraries are linked by
-        // default via `-ldylib=winapi_foo`. That is, they're linked with the
-        // `dylib` type with a `winapi_` prefix (so the winapi ones don't
-        // conflict with the system MinGW ones). This consequently means that
-        // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm
-        // DLL) when linked against *again*, for example with procedural macros
-        // or plugins, will trigger the propagation logic of `-ldylib`, passing
-        // `-lwinapi_foo` to the linker again. This isn't actually available in
-        // our distribution, however, so the link fails.
-        //
-        // To solve this problem we tell winapi to not use its bundled import
-        // libraries. This means that it will link to the system MinGW import
-        // libraries by default, and the `-ldylib=foo` directives will still get
-        // passed to the final linker, but they'll look like `-lfoo` which can
-        // be resolved because MinGW has the import library. The downside is we
-        // don't get newer functions from Windows, but we don't use any of them
-        // anyway.
-        if !mode.is_tool() {
-            cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1");
-        }
-
-        for _ in 0..self.verbosity {
-            cargo.arg("-v");
-        }
-
-        match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) {
-            (Mode::Std, Some(n), _) | (_, _, Some(n)) => {
-                cargo.env(profile_var("CODEGEN_UNITS"), n.to_string());
-            }
-            _ => {
-                // Don't set anything
-            }
-        }
-
-        if self.config.locked_deps {
-            cargo.arg("--locked");
-        }
-        if self.config.vendor || self.is_sudo {
-            cargo.arg("--frozen");
-        }
-
-        // Try to use a sysroot-relative bindir, in case it was configured absolutely.
-        cargo.env("RUSTC_INSTALL_BINDIR", self.config.bindir_relative());
-
-        cargo.force_coloring_in_ci();
-
-        // When we build Rust dylibs they're all intended for intermediate
-        // usage, so make sure we pass the -Cprefer-dynamic flag instead of
-        // linking all deps statically into the dylib.
-        if matches!(mode, Mode::Std) {
-            rustflags.arg("-Cprefer-dynamic");
-        }
-        if matches!(mode, Mode::Rustc) && !self.link_std_into_rustc_driver(target) {
-            rustflags.arg("-Cprefer-dynamic");
-        }
-
-        cargo.env(
-            "RUSTC_LINK_STD_INTO_RUSTC_DRIVER",
-            if self.link_std_into_rustc_driver(target) { "1" } else { "0" },
-        );
-
-        // When building incrementally we default to a lower ThinLTO import limit
-        // (unless explicitly specified otherwise). This will produce a somewhat
-        // slower code but give way better compile times.
-        {
-            let limit = match self.config.rust_thin_lto_import_instr_limit {
-                Some(limit) => Some(limit),
-                None if self.config.incremental => Some(10),
-                _ => None,
-            };
-
-            if let Some(limit) = limit {
-                if stage == 0
-                    || self.config.default_codegen_backend(target).unwrap_or_default() == "llvm"
-                {
-                    rustflags.arg(&format!("-Cllvm-args=-import-instr-limit={limit}"));
-                }
-            }
-        }
-
-        if matches!(mode, Mode::Std) {
-            if let Some(mir_opt_level) = self.config.rust_validate_mir_opts {
-                rustflags.arg("-Zvalidate-mir");
-                rustflags.arg(&format!("-Zmir-opt-level={mir_opt_level}"));
-            }
-            if self.config.rust_randomize_layout {
-                rustflags.arg("--cfg=randomized_layouts");
-            }
-            // Always enable inlining MIR when building the standard library.
-            // Without this flag, MIR inlining is disabled when incremental compilation is enabled.
-            // That causes some mir-opt tests which inline functions from the standard library to
-            // break when incremental compilation is enabled. So this overrides the "no inlining
-            // during incremental builds" heuristic for the standard library.
-            rustflags.arg("-Zinline-mir");
-
-            // Similarly, we need to keep debug info for functions inlined into other std functions,
-            // even if we're not going to output debuginfo for the crate we're currently building,
-            // so that it'll be available when downstream consumers of std try to use it.
-            rustflags.arg("-Zinline-mir-preserve-debug");
-        }
-
-        if self.config.rustc_parallel
-            && matches!(mode, Mode::ToolRustc | Mode::Rustc | Mode::Codegen)
-        {
-            // keep in sync with `bootstrap/lib.rs:Build::rustc_features`
-            // `cfg` option for rustc, `features` option for cargo, for conditional compilation
-            rustflags.arg("--cfg=parallel_compiler");
-            rustdocflags.arg("--cfg=parallel_compiler");
-        }
-
-        Cargo {
-            command: cargo,
-            compiler,
-            target,
-            rustflags,
-            rustdocflags,
-            hostflags,
-            allow_features,
-        }
-    }
-
     /// Ensure that a given step is built, returning its output. This will
     /// cache the step, so it is safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are built.
@@ -2399,337 +1531,3 @@ impl<'a> Builder<'a> {
         }
     }
 }
-
-/// Represents flag values in `String` form with whitespace delimiter to pass it to the compiler later.
-///
-/// `-Z crate-attr` flags will be applied recursively on the target code using the `rustc_parse::parser::Parser`.
-/// See `rustc_builtin_macros::cmdline_attrs::inject` for more information.
-#[derive(Debug, Clone)]
-struct Rustflags(String, TargetSelection);
-
-impl Rustflags {
-    fn new(target: TargetSelection) -> Rustflags {
-        let mut ret = Rustflags(String::new(), target);
-        ret.propagate_cargo_env("RUSTFLAGS");
-        ret
-    }
-
-    /// By default, cargo will pick up on various variables in the environment. However, bootstrap
-    /// reuses those variables to pass additional flags to rustdoc, so by default they get overridden.
-    /// Explicitly add back any previous value in the environment.
-    ///
-    /// `prefix` is usually `RUSTFLAGS` or `RUSTDOCFLAGS`.
-    fn propagate_cargo_env(&mut self, prefix: &str) {
-        // Inherit `RUSTFLAGS` by default ...
-        self.env(prefix);
-
-        // ... and also handle target-specific env RUSTFLAGS if they're configured.
-        let target_specific = format!("CARGO_TARGET_{}_{}", crate::envify(&self.1.triple), prefix);
-        self.env(&target_specific);
-    }
-
-    fn env(&mut self, env: &str) {
-        if let Ok(s) = env::var(env) {
-            for part in s.split(' ') {
-                self.arg(part);
-            }
-        }
-    }
-
-    fn arg(&mut self, arg: &str) -> &mut Self {
-        assert_eq!(arg.split(' ').count(), 1);
-        if !self.0.is_empty() {
-            self.0.push(' ');
-        }
-        self.0.push_str(arg);
-        self
-    }
-}
-
-/// Flags that are passed to the `rustc` shim binary.
-/// These flags will only be applied when compiling host code, i.e. when
-/// `--target` is unset.
-#[derive(Debug, Default)]
-pub struct HostFlags {
-    rustc: Vec<String>,
-}
-
-impl HostFlags {
-    const SEPARATOR: &'static str = " ";
-
-    /// Adds a host rustc flag.
-    fn arg<S: Into<String>>(&mut self, flag: S) {
-        let value = flag.into().trim().to_string();
-        assert!(!value.contains(Self::SEPARATOR));
-        self.rustc.push(value);
-    }
-
-    /// Encodes all the flags into a single string.
-    fn encode(self) -> String {
-        self.rustc.join(Self::SEPARATOR)
-    }
-}
-
-#[derive(Debug)]
-pub struct Cargo {
-    command: BootstrapCommand,
-    compiler: Compiler,
-    target: TargetSelection,
-    rustflags: Rustflags,
-    rustdocflags: Rustflags,
-    hostflags: HostFlags,
-    allow_features: String,
-}
-
-impl Cargo {
-    /// Calls `Builder::cargo` and `Cargo::configure_linker` to prepare an invocation of `cargo` to be run.
-    pub fn new(
-        builder: &Builder<'_>,
-        compiler: Compiler,
-        mode: Mode,
-        source_type: SourceType,
-        target: TargetSelection,
-        cmd_kind: Kind,
-    ) -> Cargo {
-        let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind);
-
-        match cmd_kind {
-            // No need to configure the target linker for these command types,
-            // as they don't invoke rustc at all.
-            Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {}
-            _ => {
-                cargo.configure_linker(builder);
-            }
-        }
-
-        cargo
-    }
-
-    pub fn into_cmd(self) -> BootstrapCommand {
-        self.into()
-    }
-
-    /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker`
-    pub fn new_for_mir_opt_tests(
-        builder: &Builder<'_>,
-        compiler: Compiler,
-        mode: Mode,
-        source_type: SourceType,
-        target: TargetSelection,
-        cmd_kind: Kind,
-    ) -> Cargo {
-        builder.cargo(compiler, mode, source_type, target, cmd_kind)
-    }
-
-    pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
-        self.rustdocflags.arg(arg);
-        self
-    }
-
-    pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
-        self.rustflags.arg(arg);
-        self
-    }
-
-    pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut Cargo {
-        self.command.arg(arg.as_ref());
-        self
-    }
-
-    pub fn args<I, S>(&mut self, args: I) -> &mut Cargo
-    where
-        I: IntoIterator<Item = S>,
-        S: AsRef<OsStr>,
-    {
-        for arg in args {
-            self.arg(arg.as_ref());
-        }
-        self
-    }
-
-    pub fn env(&mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> &mut Cargo {
-        // These are managed through rustflag/rustdocflag interfaces.
-        assert_ne!(key.as_ref(), "RUSTFLAGS");
-        assert_ne!(key.as_ref(), "RUSTDOCFLAGS");
-        self.command.env(key.as_ref(), value.as_ref());
-        self
-    }
-
-    pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) {
-        builder.add_rustc_lib_path(self.compiler, &mut self.command);
-    }
-
-    pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
-        self.command.current_dir(dir);
-        self
-    }
-
-    /// Adds nightly-only features that this invocation is allowed to use.
-    ///
-    /// By default, all nightly features are allowed. Once this is called, it
-    /// will be restricted to the given set.
-    pub fn allow_features(&mut self, features: &str) -> &mut Cargo {
-        if !self.allow_features.is_empty() {
-            self.allow_features.push(',');
-        }
-        self.allow_features.push_str(features);
-        self
-    }
-
-    fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
-        let target = self.target;
-        let compiler = self.compiler;
-
-        // Dealing with rpath here is a little special, so let's go into some
-        // detail. First off, `-rpath` is a linker option on Unix platforms
-        // which adds to the runtime dynamic loader path when looking for
-        // dynamic libraries. We use this by default on Unix platforms to ensure
-        // that our nightlies behave the same on Windows, that is they work out
-        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
-        // table of `config.toml`
-        //
-        // Ok, so the astute might be wondering "why isn't `-C rpath` used
-        // here?" and that is indeed a good question to ask. This codegen
-        // option is the compiler's current interface to generating an rpath.
-        // Unfortunately it doesn't quite suffice for us. The flag currently
-        // takes no value as an argument, so the compiler calculates what it
-        // should pass to the linker as `-rpath`. This unfortunately is based on
-        // the **compile time** directory structure which when building with
-        // Cargo will be very different than the runtime directory structure.
-        //
-        // All that's a really long winded way of saying that if we use
-        // `-Crpath` then the executables generated have the wrong rpath of
-        // something like `$ORIGIN/deps` when in fact the way we distribute
-        // rustc requires the rpath to be `$ORIGIN/../lib`.
-        //
-        // So, all in all, to set up the correct rpath we pass the linker
-        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
-        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
-        // to change a flag in a binary?
-        if builder.config.rpath_enabled(target) && helpers::use_host_linker(target) {
-            let libdir = builder.sysroot_libdir_relative(compiler).to_str().unwrap();
-            let rpath = if target.contains("apple") {
-                // Note that we need to take one extra step on macOS to also pass
-                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
-                // do that we pass a weird flag to the compiler to get it to do
-                // so. Note that this is definitely a hack, and we should likely
-                // flesh out rpath support more fully in the future.
-                self.rustflags.arg("-Zosx-rpath-install-name");
-                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
-            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
-                self.rustflags.arg("-Clink-args=-Wl,-z,origin");
-                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
-            } else {
-                None
-            };
-            if let Some(rpath) = rpath {
-                self.rustflags.arg(&format!("-Clink-args={rpath}"));
-            }
-        }
-
-        for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
-            self.hostflags.arg(&arg);
-        }
-
-        if let Some(target_linker) = builder.linker(target) {
-            let target = crate::envify(&target.triple);
-            self.command.env(format!("CARGO_TARGET_{target}_LINKER"), target_linker);
-        }
-        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
-        // `linker_args` here.
-        for flag in linker_flags(builder, target, LldThreads::Yes) {
-            self.rustflags.arg(&flag);
-        }
-        for arg in linker_args(builder, target, LldThreads::Yes) {
-            self.rustdocflags.arg(&arg);
-        }
-
-        if !builder.config.dry_run()
-            && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
-        {
-            self.rustflags.arg("-Clink-arg=-gz");
-        }
-
-        // Throughout the build Cargo can execute a number of build scripts
-        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
-        // obtained previously to those build scripts.
-        // Build scripts use either the `cc` crate or `configure/make` so we pass
-        // the options through environment variables that are fetched and understood by both.
-        //
-        // FIXME: the guard against msvc shouldn't need to be here
-        if target.is_msvc() {
-            if let Some(ref cl) = builder.config.llvm_clang_cl {
-                // FIXME: There is a bug in Clang 18 when building for ARM64:
-                // https://github.com/llvm/llvm-project/pull/81849. This is
-                // fixed in LLVM 19, but can't be backported.
-                if !target.starts_with("aarch64") && !target.starts_with("arm64ec") {
-                    self.command.env("CC", cl).env("CXX", cl);
-                }
-            }
-        } else {
-            let ccache = builder.config.ccache.as_ref();
-            let ccacheify = |s: &Path| {
-                let ccache = match ccache {
-                    Some(ref s) => s,
-                    None => return s.display().to_string(),
-                };
-                // FIXME: the cc-rs crate only recognizes the literal strings
-                // `ccache` and `sccache` when doing caching compilations, so we
-                // mirror that here. It should probably be fixed upstream to
-                // accept a new env var or otherwise work with custom ccache
-                // vars.
-                match &ccache[..] {
-                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
-                    _ => s.display().to_string(),
-                }
-            };
-            let triple_underscored = target.triple.replace('-', "_");
-            let cc = ccacheify(&builder.cc(target));
-            self.command.env(format!("CC_{triple_underscored}"), &cc);
-
-            let cflags = builder.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
-            self.command.env(format!("CFLAGS_{triple_underscored}"), &cflags);
-
-            if let Some(ar) = builder.ar(target) {
-                let ranlib = format!("{} s", ar.display());
-                self.command
-                    .env(format!("AR_{triple_underscored}"), ar)
-                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
-            }
-
-            if let Ok(cxx) = builder.cxx(target) {
-                let cxx = ccacheify(&cxx);
-                let cxxflags = builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
-                self.command
-                    .env(format!("CXX_{triple_underscored}"), &cxx)
-                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
-            }
-        }
-
-        self
-    }
-}
-
-impl From<Cargo> for BootstrapCommand {
-    fn from(mut cargo: Cargo) -> BootstrapCommand {
-        let rustflags = &cargo.rustflags.0;
-        if !rustflags.is_empty() {
-            cargo.command.env("RUSTFLAGS", rustflags);
-        }
-
-        let rustdocflags = &cargo.rustdocflags.0;
-        if !rustdocflags.is_empty() {
-            cargo.command.env("RUSTDOCFLAGS", rustdocflags);
-        }
-
-        let encoded_hostflags = cargo.hostflags.encode();
-        if !encoded_hostflags.is_empty() {
-            cargo.command.env("RUSTC_HOST_FLAGS", encoded_hostflags);
-        }
-
-        if !cargo.allow_features.is_empty() {
-            cargo.command.env("RUSTC_ALLOW_FEATURES", cargo.allow_features);
-        }
-        cargo.command
-    }
-}
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 695a66834d4..21c5f7232a1 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -637,7 +637,7 @@ mod dist {
         assert_eq!(first(builder.cache.all::<test::Crate>()), &[test::Crate {
             compiler: Compiler { host, stage: 0 },
             target: host,
-            mode: Mode::Std,
+            mode: crate::Mode::Std,
             crates: vec!["std".to_owned()],
         },]);
     }
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index f4c00d8287d..00f83237224 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -190,15 +190,6 @@ fn is_same_generics<'tcx>(
         .enumerate()
         .skip(1) // skip `Self` implicit arg
         .all(|(arg_index, arg)| {
-            if [
-                implied_by_generics.host_effect_index,
-                implied_generics.host_effect_index,
-            ]
-            .contains(&Some(arg_index))
-            {
-                // skip host effect params in determining whether generics are same
-                return true;
-            }
             if let Some(ty) = arg.as_type() {
                 if let &ty::Param(ty::ParamTy { index, .. }) = ty.kind()
                     // `index == 0` means that it's referring to `Self`,
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 21793f761d9..07c3d0eada0 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -274,23 +274,10 @@ pub fn implements_trait_with_env_from_iter<'tcx>(
         .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
         .collect::<Vec<_>>();
 
-    // If an effect arg was not specified, we need to specify it.
-    let effect_arg = if tcx
-        .generics_of(trait_id)
-        .host_effect_index
-        .is_some_and(|x| args.get(x - 1).is_none())
-    {
-        Some(GenericArg::from(callee_id.map_or(tcx.consts.true_, |def_id| {
-            tcx.expected_host_effect_param_for_body(def_id)
-        })))
-    } else {
-        None
-    };
-
     let trait_ref = TraitRef::new(
         tcx,
         trait_id,
-        [GenericArg::from(ty)].into_iter().chain(args).chain(effect_arg),
+        [GenericArg::from(ty)].into_iter().chain(args),
     );
 
     debug_assert_matches!(
diff --git a/tests/ui/argument-suggestions/issue-109425.fixed b/tests/ui/argument-suggestions/issue-109425.fixed
index 5d96f457c88..4b3aaa46d86 100644
--- a/tests/ui/argument-suggestions/issue-109425.fixed
+++ b/tests/ui/argument-suggestions/issue-109425.fixed
@@ -15,6 +15,10 @@ fn main() {
     //~^ error: this function takes 1 argument but 3 arguments were supplied
     is(0, ""); // is(0, "")
     //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    is(1, "");
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    is(1, "");
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
     s("");     // s("")
     //~^ error: this function takes 1 argument but 3 arguments were supplied
 }
diff --git a/tests/ui/argument-suggestions/issue-109425.rs b/tests/ui/argument-suggestions/issue-109425.rs
index bb9d37ee0ff..56816681337 100644
--- a/tests/ui/argument-suggestions/issue-109425.rs
+++ b/tests/ui/argument-suggestions/issue-109425.rs
@@ -15,6 +15,10 @@ fn main() {
     //~^ error: this function takes 1 argument but 3 arguments were supplied
     is(0, 1, 2, ""); // is(0, "")
     //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    is((), 1, "", ());
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
+    is(1, (), "", ());
+    //~^ error: this function takes 2 arguments but 4 arguments were supplied
     s(0, 1, "");     // s("")
     //~^ error: this function takes 1 argument but 3 arguments were supplied
 }
diff --git a/tests/ui/argument-suggestions/issue-109425.stderr b/tests/ui/argument-suggestions/issue-109425.stderr
index bfe007793d4..2cd53ed528e 100644
--- a/tests/ui/argument-suggestions/issue-109425.stderr
+++ b/tests/ui/argument-suggestions/issue-109425.stderr
@@ -74,9 +74,47 @@ LL -     is(0, 1, 2, ""); // is(0, "")
 LL +     is(0, ""); // is(0, "")
    |
 
-error[E0061]: this function takes 1 argument but 3 arguments were supplied
+error[E0061]: this function takes 2 arguments but 4 arguments were supplied
   --> $DIR/issue-109425.rs:18:5
    |
+LL |     is((), 1, "", ());
+   |     ^^ --         -- unexpected argument #4 of type `()`
+   |        |
+   |        unexpected argument #1 of type `()`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:5:4
+   |
+LL | fn is(_: u32, _: &str) {}
+   |    ^^ ------  -------
+help: remove the extra arguments
+   |
+LL -     is((), 1, "", ());
+LL +     is(1, "");
+   |
+
+error[E0061]: this function takes 2 arguments but 4 arguments were supplied
+  --> $DIR/issue-109425.rs:20:5
+   |
+LL |     is(1, (), "", ());
+   |     ^^    --      -- unexpected argument #4 of type `()`
+   |           |
+   |           unexpected argument #2 of type `()`
+   |
+note: function defined here
+  --> $DIR/issue-109425.rs:5:4
+   |
+LL | fn is(_: u32, _: &str) {}
+   |    ^^ ------  -------
+help: remove the extra arguments
+   |
+LL -     is(1, (), "", ());
+LL +     is(1, "");
+   |
+
+error[E0061]: this function takes 1 argument but 3 arguments were supplied
+  --> $DIR/issue-109425.rs:22:5
+   |
 LL |     s(0, 1, "");     // s("")
    |     ^ -  - unexpected argument #2 of type `{integer}`
    |       |
@@ -93,6 +131,6 @@ LL -     s(0, 1, "");     // s("")
 LL +     s("");     // s("")
    |
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/argument-suggestions/issue-112507.stderr b/tests/ui/argument-suggestions/issue-112507.stderr
index 908ed35c669..e2ea9af7dc2 100644
--- a/tests/ui/argument-suggestions/issue-112507.stderr
+++ b/tests/ui/argument-suggestions/issue-112507.stderr
@@ -18,8 +18,9 @@ LL |     Float(Option<f64>),
    |     ^^^^^
 help: remove the extra arguments
    |
-LL ~         ,
-LL ~         None);
+LL -         0,
+LL -         None,
+LL +         None);
    |
 
 error: aborting due to 1 previous error