about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbit-aloo <sshourya17@gmail.com>2025-08-20 23:24:53 +0530
committerbit-aloo <sshourya17@gmail.com>2025-08-20 23:24:53 +0530
commit433dc2be446c1532f764f410e868a7d7d3b0b07c (patch)
tree578192ce4dac45cf775c67bf55c8055ce11fc7a6
parent5ae81c984f35ed0e4334c57287ac1fbf2467dd5f (diff)
downloadrust-433dc2be446c1532f764f410e868a7d7d3b0b07c.tar.gz
rust-433dc2be446c1532f764f410e868a7d7d3b0b07c.zip
make download context lean and remove mutable types
-rw-r--r--src/bootstrap/src/core/config/config.rs98
-rw-r--r--src/bootstrap/src/core/download.rs70
2 files changed, 89 insertions, 79 deletions
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 9d8f97196b6..5913c871d83 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -679,15 +679,11 @@ impl Config {
             .unwrap_or_else(|| vec![host_target]);
 
         let llvm_assertions = llvm_assertions_.unwrap_or(false);
-
         let mut target_config = HashMap::new();
-        let mut download_rustc_commit = None;
-        let mut llvm_from_ci = false;
         let mut channel = "dev".to_string();
         let mut out = flags_build_dir
             .or(build_build_dir.map(PathBuf::from))
             .unwrap_or_else(|| PathBuf::from("build"));
-        let mut rust_info = GitInfo::Absent;
 
         if cfg!(test) {
             // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly.
@@ -730,16 +726,11 @@ impl Config {
             );
         }
 
-        let mut dwn_ctx = DownloadContext {
+        let dwn_ctx = DownloadContext {
             path_modification_cache: path_modification_cache.clone(),
             src: &src,
-            rust_info: rust_info.clone(),
             submodules: &build_submodules,
-            download_rustc_commit: download_rustc_commit.clone(),
             host_target,
-            llvm_from_ci,
-            target_config: target_config.clone(),
-            out: out.clone(),
             patch_binaries_for_nix: build_patch_binaries_for_nix,
             exec_ctx: &exec_ctx,
             stage0_metadata: &stage0_metadata,
@@ -749,7 +740,7 @@ impl Config {
         };
 
         let initial_rustc = build_rustc.unwrap_or_else(|| {
-            download_beta_toolchain(&dwn_ctx);
+            download_beta_toolchain(&dwn_ctx, &out);
             out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target))
         });
 
@@ -763,7 +754,7 @@ impl Config {
         ));
 
         let initial_cargo = build_cargo.unwrap_or_else(|| {
-            download_beta_toolchain(&dwn_ctx);
+            download_beta_toolchain(&dwn_ctx, &out);
             initial_sysroot.join("bin").join(exe("cargo", host_target))
         });
 
@@ -771,7 +762,6 @@ impl Config {
         if exec_ctx.dry_run() {
             out = out.join("tmp-dry-run");
             fs::create_dir_all(&out).expect("Failed to create dry-run directory");
-            dwn_ctx.out = out.clone();
         }
 
         let file_content = t!(fs::read_to_string(src.join("src/ci/channel")));
@@ -791,8 +781,7 @@ impl Config {
 
         let omit_git_hash = rust_omit_git_hash.unwrap_or(channel == "dev");
 
-        rust_info = git_info(&exec_ctx, omit_git_hash, &src);
-        dwn_ctx.rust_info = rust_info.clone();
+        let rust_info = git_info(&exec_ctx, omit_git_hash, &src);
 
         if !is_user_configured_rust_channel && rust_info.is_from_tarball() {
             channel = ci_channel.into();
@@ -823,9 +812,8 @@ impl Config {
             );
         }
 
-        download_rustc_commit =
-            download_ci_rustc_commit(&dwn_ctx, rust_download_rustc, llvm_assertions);
-        dwn_ctx.download_rustc_commit = download_rustc_commit.clone();
+        let mut download_rustc_commit =
+            download_ci_rustc_commit(&dwn_ctx, &rust_info, rust_download_rustc, llvm_assertions);
 
         if debug_assertions_requested && download_rustc_commit.is_some() {
             eprintln!(
@@ -834,7 +822,6 @@ impl Config {
             );
             // We need to put this later down_ci_rustc_commit.
             download_rustc_commit = None;
-            dwn_ctx.download_rustc_commit = None;
         }
 
         // We need to override `rust.channel` if it's manually specified when using the CI rustc.
@@ -847,9 +834,10 @@ impl Config {
                 "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel."
             );
 
-            channel = read_file_by_commit(&dwn_ctx, Path::new("src/ci/channel"), commit)
-                .trim()
-                .to_owned();
+            channel =
+                read_file_by_commit(&dwn_ctx, &rust_info, Path::new("src/ci/channel"), commit)
+                    .trim()
+                    .to_owned();
         }
 
         if let Some(t) = toml.target {
@@ -911,11 +899,15 @@ impl Config {
 
                 target_config.insert(TargetSelection::from_user(&triple), target);
             }
-            dwn_ctx.target_config = target_config.clone();
         }
 
-        llvm_from_ci = parse_download_ci_llvm(&dwn_ctx, llvm_download_ci_llvm, llvm_assertions);
-        dwn_ctx.llvm_from_ci = llvm_from_ci;
+        let llvm_from_ci = parse_download_ci_llvm(
+            &dwn_ctx,
+            &rust_info,
+            &download_rustc_commit,
+            llvm_download_ci_llvm,
+            llvm_assertions,
+        );
 
         // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
         // build our internal lld and use it as the default linker, by setting the `rust.lld` config
@@ -976,18 +968,16 @@ impl Config {
 
         if llvm_from_ci {
             let triple = &host_target.triple;
-            let ci_llvm_bin = ci_llvm_root(&dwn_ctx).join("bin");
+            let ci_llvm_bin = ci_llvm_root(&dwn_ctx, llvm_from_ci, &out).join("bin");
             let build_target =
                 target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple));
-            dwn_ctx.target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple));
-
             check_ci_llvm!(build_target.llvm_config);
             check_ci_llvm!(build_target.llvm_filecheck);
             build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", host_target)));
             build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target)));
         }
 
-        let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx));
+        let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out));
 
         if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained)
             && !lld_enabled
@@ -998,7 +988,7 @@ impl Config {
             );
         }
 
-        if lld_enabled && is_system_llvm(&dwn_ctx, host_target) {
+        if lld_enabled && is_system_llvm(&dwn_ctx, &target_config, llvm_from_ci, host_target) {
             panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config.");
         }
 
@@ -1392,7 +1382,7 @@ impl Config {
     /// Returns the content of the given file at a specific commit.
     pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String {
         let dwn_ctx = DownloadContext::from(self);
-        read_file_by_commit(dwn_ctx, file, commit)
+        read_file_by_commit(dwn_ctx, &self.rust_info, file, commit)
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -1464,7 +1454,7 @@ impl Config {
     /// The absolute path to the downloaded LLVM artifacts.
     pub(crate) fn ci_llvm_root(&self) -> PathBuf {
         let dwn_ctx = DownloadContext::from(self);
-        ci_llvm_root(dwn_ctx)
+        ci_llvm_root(dwn_ctx, self.llvm_from_ci, &self.out)
     }
 
     /// Directory where the extracted `rustc-dev` component is stored.
@@ -1628,7 +1618,7 @@ impl Config {
     )]
     pub(crate) fn update_submodule(&self, relative_path: &str) {
         let dwn_ctx = DownloadContext::from(self);
-        update_submodule(dwn_ctx, relative_path);
+        update_submodule(dwn_ctx, &self.rust_info, relative_path);
     }
 
     /// Returns true if any of the `paths` have been modified locally.
@@ -1744,7 +1734,7 @@ impl Config {
     /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
     pub fn is_system_llvm(&self, target: TargetSelection) -> bool {
         let dwn_ctx = DownloadContext::from(self);
-        is_system_llvm(dwn_ctx, target)
+        is_system_llvm(dwn_ctx, &self.target_config, self.llvm_from_ci, target)
     }
 
     /// Returns `true` if this is our custom, patched, version of LLVM.
@@ -2038,6 +2028,7 @@ pub fn check_stage0_version(
 
 pub fn download_ci_rustc_commit<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    rust_info: &channel::GitInfo,
     download_rustc: Option<StringOrBool>,
     llvm_assertions: bool,
 ) -> Option<String> {
@@ -2057,7 +2048,7 @@ pub fn download_ci_rustc_commit<'a>(
         None | Some(StringOrBool::Bool(false)) => return None,
         Some(StringOrBool::Bool(true)) => false,
         Some(StringOrBool::String(s)) if s == "if-unchanged" => {
-            if !dwn_ctx.rust_info.is_managed_git_subrepository() {
+            if !rust_info.is_managed_git_subrepository() {
                 println!(
                     "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources."
                 );
@@ -2071,7 +2062,7 @@ pub fn download_ci_rustc_commit<'a>(
         }
     };
 
-    let commit = if dwn_ctx.rust_info.is_managed_git_subrepository() {
+    let commit = if rust_info.is_managed_git_subrepository() {
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
         let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
@@ -2145,6 +2136,8 @@ pub fn git_config(stage0_metadata: &build_helper::stage0_parser::Stage0) -> GitC
 
 pub fn parse_download_ci_llvm<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    rust_info: &channel::GitInfo,
+    download_rustc_commit: &Option<String>,
     download_ci_llvm: Option<StringOrBool>,
     asserts: bool,
 ) -> bool {
@@ -2160,7 +2153,7 @@ pub fn parse_download_ci_llvm<'a>(
     let download_ci_llvm = download_ci_llvm.unwrap_or(default);
 
     let if_unchanged = || {
-        if dwn_ctx.rust_info.is_from_tarball() {
+        if rust_info.is_from_tarball() {
             // Git is needed for running "if-unchanged" logic.
             println!("ERROR: 'if-unchanged' is only compatible with Git managed sources.");
             crate::exit!(1);
@@ -2168,7 +2161,7 @@ pub fn parse_download_ci_llvm<'a>(
 
         // Fetching the LLVM submodule is unnecessary for self-tests.
         #[cfg(not(test))]
-        update_submodule(dwn_ctx, "src/llvm-project");
+        update_submodule(dwn_ctx, rust_info, "src/llvm-project");
 
         // Check for untracked changes in `src/llvm-project` and other important places.
         let has_changes = has_changes_from_upstream(dwn_ctx, LLVM_INVALIDATION_PATHS);
@@ -2183,7 +2176,7 @@ pub fn parse_download_ci_llvm<'a>(
 
     match download_ci_llvm {
         StringOrBool::Bool(b) => {
-            if !b && dwn_ctx.download_rustc_commit.is_some() {
+            if !b && download_rustc_commit.is_some() {
                 panic!(
                     "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`."
                 );
@@ -2226,9 +2219,13 @@ pub fn has_changes_from_upstream<'a>(
         fields(relative_path = ?relative_path),
     ),
 )]
-pub(crate) fn update_submodule<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, relative_path: &str) {
+pub(crate) fn update_submodule<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    rust_info: &channel::GitInfo,
+    relative_path: &str,
+) {
     let dwn_ctx = dwn_ctx.as_ref();
-    if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, &dwn_ctx.rust_info) {
+    if rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, rust_info) {
         return;
     }
 
@@ -2357,12 +2354,14 @@ pub fn submodules_(submodules: &Option<bool>, rust_info: &channel::GitInfo) -> b
 /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
 pub fn is_system_llvm<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    target_config: &HashMap<TargetSelection, Target>,
+    llvm_from_ci: bool,
     target: TargetSelection,
 ) -> bool {
     let dwn_ctx = dwn_ctx.as_ref();
-    match dwn_ctx.target_config.get(&target) {
+    match target_config.get(&target) {
         Some(Target { llvm_config: Some(_), .. }) => {
-            let ci_llvm = dwn_ctx.llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target);
+            let ci_llvm = llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target);
             !ci_llvm
         }
         // We're building from the in-tree src/llvm-project sources.
@@ -2375,21 +2374,26 @@ pub fn is_host_target(host_target: &TargetSelection, target: &TargetSelection) -
     host_target == target
 }
 
-pub(crate) fn ci_llvm_root<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) -> PathBuf {
+pub(crate) fn ci_llvm_root<'a>(
+    dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    llvm_from_ci: bool,
+    out: &Path,
+) -> PathBuf {
     let dwn_ctx = dwn_ctx.as_ref();
-    assert!(dwn_ctx.llvm_from_ci);
-    dwn_ctx.out.join(dwn_ctx.host_target).join("ci-llvm")
+    assert!(llvm_from_ci);
+    out.join(dwn_ctx.host_target).join("ci-llvm")
 }
 
 /// Returns the content of the given file at a specific commit.
 pub(crate) fn read_file_by_commit<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    rust_info: &channel::GitInfo,
     file: &Path,
     commit: &str,
 ) -> String {
     let dwn_ctx = dwn_ctx.as_ref();
     assert!(
-        dwn_ctx.rust_info.is_managed_git_subrepository(),
+        rust_info.is_managed_git_subrepository(),
         "`Config::read_file_by_commit` is not supported in non-git sources."
     );
 
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 402d6019dab..2f3c80559c0 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -9,9 +9,8 @@ use std::sync::{Arc, Mutex, OnceLock};
 use build_helper::git::PathFreshness;
 use xz2::bufread::XzDecoder;
 
-use crate::core::config::{BUILDER_CONFIG_FILENAME, Target, TargetSelection};
+use crate::core::config::{BUILDER_CONFIG_FILENAME, TargetSelection};
 use crate::utils::build_stamp::BuildStamp;
-use crate::utils::channel;
 use crate::utils::exec::{ExecutionContext, command};
 use crate::utils::helpers::{exe, hex_encode, move_file};
 use crate::{Config, t};
@@ -73,7 +72,7 @@ impl Config {
 
     fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
         let dwn_ctx: DownloadContext<'_> = self.into();
-        download_file(dwn_ctx, url, dest_path, help_on_error);
+        download_file(dwn_ctx, &self.out, url, dest_path, help_on_error);
     }
 
     fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) {
@@ -238,7 +237,7 @@ impl Config {
         destination: &str,
     ) {
         let dwn_ctx: DownloadContext<'_> = self.into();
-        download_component(dwn_ctx, mode, filename, prefix, key, destination);
+        download_component(dwn_ctx, &self.out, mode, filename, prefix, key, destination);
     }
 
     #[cfg(test)]
@@ -403,13 +402,8 @@ impl Config {
 pub(crate) struct DownloadContext<'a> {
     pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>,
     pub src: &'a Path,
-    pub rust_info: channel::GitInfo,
     pub submodules: &'a Option<bool>,
-    pub download_rustc_commit: Option<String>,
     pub host_target: TargetSelection,
-    pub llvm_from_ci: bool,
-    pub target_config: HashMap<TargetSelection, Target>,
-    pub out: PathBuf,
     pub patch_binaries_for_nix: Option<bool>,
     pub exec_ctx: &'a ExecutionContext,
     pub stage0_metadata: &'a build_helper::stage0_parser::Stage0,
@@ -430,12 +424,7 @@ impl<'a> From<&'a Config> for DownloadContext<'a> {
             path_modification_cache: value.path_modification_cache.clone(),
             src: &value.src,
             host_target: value.host_target,
-            rust_info: value.rust_info.clone(),
-            download_rustc_commit: value.download_rustc_commit.clone(),
             submodules: &value.submodules,
-            llvm_from_ci: value.llvm_from_ci,
-            target_config: value.target_config.clone(),
-            out: value.out.clone(),
             patch_binaries_for_nix: value.patch_binaries_for_nix,
             exec_ctx: &value.exec_ctx,
             stage0_metadata: &value.stage0_metadata,
@@ -495,6 +484,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo
 #[cfg(test)]
 pub(crate) fn maybe_download_rustfmt<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    out: &Path,
 ) -> Option<PathBuf> {
     Some(PathBuf::new())
 }
@@ -504,6 +494,7 @@ pub(crate) fn maybe_download_rustfmt<'a>(
 #[cfg(not(test))]
 pub(crate) fn maybe_download_rustfmt<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    out: &Path,
 ) -> Option<PathBuf> {
     use build_helper::stage0_parser::VersionMetadata;
 
@@ -517,7 +508,7 @@ pub(crate) fn maybe_download_rustfmt<'a>(
     let channel = format!("{version}-{date}");
 
     let host = dwn_ctx.host_target;
-    let bin_root = dwn_ctx.out.join(host).join("rustfmt");
+    let bin_root = out.join(host).join("rustfmt");
     let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
     let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel);
     if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() {
@@ -526,6 +517,7 @@ pub(crate) fn maybe_download_rustfmt<'a>(
 
     download_component(
         dwn_ctx,
+        out,
         DownloadSource::Dist,
         format!("rustfmt-{version}-{build}.tar.xz", build = host.triple),
         "rustfmt-preview",
@@ -535,6 +527,7 @@ pub(crate) fn maybe_download_rustfmt<'a>(
 
     download_component(
         dwn_ctx,
+        out,
         DownloadSource::Dist,
         format!("rustc-{version}-{build}.tar.xz", build = host.triple),
         "rustc",
@@ -543,13 +536,13 @@ pub(crate) fn maybe_download_rustfmt<'a>(
     );
 
     if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) {
-        fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx);
-        fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx);
+        fix_bin_or_dylib(out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx);
+        fix_bin_or_dylib(out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx);
         let lib_dir = bin_root.join("lib");
         for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
             let lib = t!(lib);
             if path_is_dylib(&lib.path()) {
-                fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx);
+                fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx);
             }
         }
     }
@@ -559,10 +552,10 @@ pub(crate) fn maybe_download_rustfmt<'a>(
 }
 
 #[cfg(test)]
-pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) {}
+pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) {}
 
 #[cfg(not(test))]
-pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) {
+pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) {
     let dwn_ctx = dwn_ctx.as_ref();
     dwn_ctx.exec_ctx.verbose(|| {
         println!("downloading stage0 beta artifacts");
@@ -574,6 +567,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a
     let sysroot = "stage0";
     download_toolchain(
         dwn_ctx,
+        out,
         &version,
         sysroot,
         &date,
@@ -583,8 +577,10 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a
     );
 }
 
+#[allow(clippy::too_many_arguments)]
 fn download_toolchain<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    out: &Path,
     version: &str,
     sysroot: &str,
     stamp_key: &str,
@@ -594,7 +590,7 @@ fn download_toolchain<'a>(
 ) {
     let dwn_ctx = dwn_ctx.as_ref();
     let host = dwn_ctx.host_target.triple;
-    let bin_root = dwn_ctx.out.join(host).join(sysroot);
+    let bin_root = out.join(host).join(sysroot);
     let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key);
 
     if !bin_root.join("bin").join(exe("rustc", dwn_ctx.host_target)).exists()
@@ -605,20 +601,28 @@ fn download_toolchain<'a>(
         }
         let filename = format!("rust-std-{version}-{host}.tar.xz");
         let pattern = format!("rust-std-{host}");
-        download_component(dwn_ctx, mode.clone(), filename, &pattern, stamp_key, destination);
+        download_component(dwn_ctx, out, mode.clone(), filename, &pattern, stamp_key, destination);
         let filename = format!("rustc-{version}-{host}.tar.xz");
-        download_component(dwn_ctx, mode.clone(), filename, "rustc", stamp_key, destination);
+        download_component(dwn_ctx, out, mode.clone(), filename, "rustc", stamp_key, destination);
 
         for component in extra_components {
             let filename = format!("{component}-{version}-{host}.tar.xz");
-            download_component(dwn_ctx, mode.clone(), filename, component, stamp_key, destination);
+            download_component(
+                dwn_ctx,
+                out,
+                mode.clone(),
+                filename,
+                component,
+                stamp_key,
+                destination,
+            );
         }
 
         if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) {
-            fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx);
-            fix_bin_or_dylib(&dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx);
+            fix_bin_or_dylib(out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx);
+            fix_bin_or_dylib(out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx);
             fix_bin_or_dylib(
-                &dwn_ctx.out,
+                out,
                 &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"),
                 dwn_ctx.exec_ctx,
             );
@@ -626,7 +630,7 @@ fn download_toolchain<'a>(
             for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) {
                 let lib = t!(lib);
                 if path_is_dylib(&lib.path()) {
-                    fix_bin_or_dylib(&dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx);
+                    fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx);
                 }
             }
         }
@@ -750,6 +754,7 @@ fn should_fix_bins_and_dylibs(
 
 fn download_component<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    out: &Path,
     mode: DownloadSource,
     filename: String,
     prefix: &str,
@@ -763,14 +768,14 @@ fn download_component<'a>(
     }
 
     let cache_dst =
-        dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| dwn_ctx.out.join("cache"));
+        dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| out.join("cache"));
 
     let cache_dir = cache_dst.join(key);
     if !cache_dir.exists() {
         t!(fs::create_dir_all(&cache_dir));
     }
 
-    let bin_root = dwn_ctx.out.join(dwn_ctx.host_target).join(destination);
+    let bin_root = out.join(dwn_ctx.host_target).join(destination);
     let tarball = cache_dir.join(&filename);
     let (base_url, url, should_verify) = match mode {
         DownloadSource::CI => {
@@ -835,7 +840,7 @@ HELP: if trying to compile an old commit of rustc, disable `download-rustc` in b
 download-rustc = false
 ";
     }
-    download_file(dwn_ctx, &format!("{base_url}/{url}"), &tarball, help_on_error);
+    download_file(dwn_ctx, out, &format!("{base_url}/{url}"), &tarball, help_on_error);
     if let Some(sha256) = checksum
         && !verify(dwn_ctx.exec_ctx, &tarball, sha256)
     {
@@ -953,6 +958,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str
 
 fn download_file<'a>(
     dwn_ctx: impl AsRef<DownloadContext<'a>>,
+    out: &Path,
     url: &str,
     dest_path: &Path,
     help_on_error: &str,
@@ -963,7 +969,7 @@ fn download_file<'a>(
         println!("download {url}");
     });
     // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/.
-    let tempfile = tempdir(&dwn_ctx.out).join(dest_path.file_name().unwrap());
+    let tempfile = tempdir(out).join(dest_path.file_name().unwrap());
     // While bootstrap itself only supports http and https downloads, downstream forks might
     // need to download components from other protocols. The match allows them adding more
     // protocols without worrying about merge conflicts if we change the HTTP implementation.