From 8402d542626ff45449ae6c53790838cd0bbc4743 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 7 Jul 2026 11:28:43 +0200 Subject: [PATCH 01/18] Upgrade platforms to 4 --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- src/dist/target_tuple/known.rs | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c4ab9ec825..8206818261 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,9 +1652,9 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "platforms" -version = "3.12.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9245c6e7c5a6bcdd7977fdf6d1e1c67f4cc2d0d58c041df0ea5940953033e6ca" +checksum = "c1edb60d9efe54a87684d4d6217f612ecd22976ec9220e3e3ad78df2deeefc31" [[package]] name = "portable-atomic" diff --git a/Cargo.toml b/Cargo.toml index 2110cb28d8..f948012b20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,7 @@ openssl-src = { version = "=300.5.4", optional = true } opentelemetry = { version = "0.32", optional = true } opentelemetry-otlp = { version = "0.32", features = ["grpc-tonic"], optional = true } opentelemetry_sdk = { version = "0.32", features = ["rt-tokio"], optional = true } -platforms = "3.4" +platforms = "4" pulldown-cmark = { version = "0.13", default-features = false } rand = "0.10" rayon = "1.10.0" @@ -155,7 +155,7 @@ tokio-rustls = "0.26.4" webpki-root-certs = "1" [build-dependencies] -platforms = "3.4" +platforms = "4" [lints.rust] rust_2018_idioms = { level = "deny", priority = -1 } diff --git a/src/dist/target_tuple/known.rs b/src/dist/target_tuple/known.rs index b034a77211..fbcf35f455 100644 --- a/src/dist/target_tuple/known.rs +++ b/src/dist/target_tuple/known.rs @@ -108,9 +108,11 @@ pub static LIST_OSES: &[&str] = &[ "nuttx-eabi", "nuttx-eabihf", "nvidia-cuda", + "oe-linux", "openwrt-linux", "pc-cygwin", "pc-nto", + "pc-qnx", "pc-solaris", "pc-windows", "risc0-zkvm", @@ -138,6 +140,7 @@ pub static LIST_OSES: &[&str] = &[ "unknown-nto", "unknown-nuttx", "unknown-openbsd", + "unknown-qnx", "unknown-qurt", "unknown-redox", "unknown-teeos", @@ -187,10 +190,10 @@ pub static LIST_ENVS: &[&str] = &[ "newlibeabihf", "none", "ohos", + "pauthtest", "qnx700", "qnx710", "qnx710_iosock", - "qnx800", "sgx", "sim", "softfloat", From 48bb4e6b6d211ba620be004f7f5cdda42b9f0147 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Tue, 7 Jul 2026 11:29:02 +0200 Subject: [PATCH 02/18] Take semver-compatible dependency updates --- Cargo.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8206818261..8b130acadd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,9 +442,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -452,18 +452,18 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crypto-common" @@ -1267,11 +1267,11 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] @@ -2159,9 +2159,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" @@ -3316,18 +3316,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" dependencies = [ "proc-macro2", "quote", From e216ab299beedbd41646b5d27fe7aac1b41338c8 Mon Sep 17 00:00:00 2001 From: Lea Fairbanks Date: Wed, 8 Jul 2026 00:37:14 -0600 Subject: [PATCH 03/18] uninstalls toolchains prior to deleting the rustup home folder --- src/cli/rustup_mode.rs | 2 +- src/cli/self_update.rs | 20 +++++++++++++++----- tests/suite/cli_self_upd.rs | 22 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 343eccd504..57e267ffcc 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -812,7 +812,7 @@ pub async fn main( SelfSubcmd::Uninstall { no_prompt, no_modify_path, - } => self_update::uninstall(no_prompt, no_modify_path, process), + } => self_update::uninstall(no_prompt, no_modify_path, cfg), SelfSubcmd::UpgradeData => cfg.upgrade_data().map(|_| ExitCode::SUCCESS), }, RustupSubcmd::Set { subcmd } => match subcmd { diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index cfe7ef0ed5..96fc010553 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -1047,17 +1047,22 @@ async fn maybe_install_rust(opts: InstallOpts<'_>, cfg: &mut Cfg<'_>) -> Result< Ok(()) } -pub(crate) fn uninstall( - no_prompt: bool, - no_modify_path: bool, - process: &Process, -) -> Result { +/// Uninstall process: +/// 1. Remove all installed toolchains. +/// 2. Remove rustup home. +/// 3. Remove all entries in `$CARGO_HOME` except `bin`. +/// 4. Remove rustup tool links and binary. +/// 5. Try to remove $CARGO_HOME/bin directory if it's empty. +/// 6. Upon successfully removing $CARGO_HOME/bin, clean up $PATH. +/// 7. Try to remove $CARGO_HOME directory if it's empty. +pub(crate) fn uninstall(no_prompt: bool, no_modify_path: bool, cfg: &Cfg<'_>) -> Result { if cfg!(feature = "no-self-update") { error!("self-uninstall is disabled for this build of rustup"); error!("you should probably use your system package manager to uninstall rustup"); return Ok(ExitCode::FAILURE); } + let process = cfg.process; let cargo_home = process.cargo_home()?; if !cargo_home.join(format!("bin/rustup{EXE_SUFFIX}")).exists() { @@ -1081,6 +1086,11 @@ pub(crate) fn uninstall( } } + info!("removing toolchains"); + for toolchain in cfg.list_toolchains()? { + Toolchain::ensure_removed(cfg, toolchain.into())?; + } + info!("removing rustup home"); // Delete RUSTUP_HOME diff --git a/tests/suite/cli_self_upd.rs b/tests/suite/cli_self_upd.rs index 72ca1d47e5..575bc7d2ec 100644 --- a/tests/suite/cli_self_upd.rs +++ b/tests/suite/cli_self_upd.rs @@ -204,6 +204,28 @@ async fn uninstall_deletes_bins() { assert!(!rust_gdbgui.exists()); } +#[tokio::test] +async fn uninstall_deletes_installed_toolchains() { + let cx = setup_empty_installed().await; + let path = cx.config.customdir.join("custom-1"); + let path = path.to_string_lossy(); + cx.config + .expect(["rustup", "toolchain", "link", "custom", &path]) + .await + .is_ok(); + cx.config + .expect(["rustup", "self", "uninstall", "-y"]) + .await + .with_stderr(snapbox::str![[r#" +... +info: uninstalling toolchain custom +info: toolchain custom uninstalled +... +"#]]) + .is_ok(); + assert!(!cx.config.rustupdir.join("toolchains").exists()); +} + #[tokio::test] async fn uninstall_works_if_some_bins_dont_exist() { let cx = setup_empty_installed().await; From 518065f7a3d05a2ed956e6eefad8df8156da8fb9 Mon Sep 17 00:00:00 2001 From: ychampion Date: Thu, 9 Jul 2026 14:07:41 +0000 Subject: [PATCH 04/18] Fix Rust 1.97 clippy warnings --- tests/suite/cli_rustup.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/suite/cli_rustup.rs b/tests/suite/cli_rustup.rs index 91c3891907..3b2dc1889c 100644 --- a/tests/suite/cli_rustup.rs +++ b/tests/suite/cli_rustup.rs @@ -353,7 +353,7 @@ async fn add_target() { let cx = CliTestContext::new(Scenario::SimpleV2).await; let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); cx.config @@ -372,7 +372,7 @@ async fn remove_target() { let cx = CliTestContext::new(Scenario::SimpleV2).await; let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); cx.config @@ -404,13 +404,13 @@ async fn add_remove_multiple_targets() { .is_ok(); let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); assert!(cx.config.rustupdir.has(path)); let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH2 ); assert!(cx.config.rustupdir.has(path)); @@ -421,13 +421,13 @@ async fn add_remove_multiple_targets() { .is_ok(); let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); assert!(!cx.config.rustupdir.has(path)); let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH2 ); assert!(!cx.config.rustupdir.has(path)); @@ -474,7 +474,7 @@ async fn add_target_explicit() { let cx = CliTestContext::new(Scenario::SimpleV2).await; let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); cx.config @@ -500,7 +500,7 @@ async fn remove_target_explicit() { let cx = CliTestContext::new(Scenario::SimpleV2).await; let path = format!( "toolchains/nightly-{}/lib/rustlib/{}/lib/libstd.rlib", - &this_host_tuple(), + this_host_tuple(), CROSS_ARCH1 ); cx.config From 97ca3679b0f0c5d948fde1e4f947029b102fdc4b Mon Sep 17 00:00:00 2001 From: ychampion Date: Thu, 9 Jul 2026 13:31:02 +0000 Subject: [PATCH 05/18] fix: Lock state file updates --- src/settings.rs | 4 ++-- src/utils/mod.rs | 14 +++++++++++++ src/utils/raw.rs | 52 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/settings.rs b/src/settings.rs index 42dc7ceebf..d4e45fbacd 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -29,7 +29,7 @@ impl SettingsFile { fn write_settings(&self) -> Result<()> { let settings = self.cache.borrow(); - utils::write_file( + utils::write_locked_file( "settings", &self.path, &settings.as_ref().unwrap().stringify()?, @@ -44,7 +44,7 @@ impl SettingsFile { if b.is_none() { drop(b); *self.cache.borrow_mut() = Some(if utils::is_file(&self.path) { - let content = utils::read_file("settings", &self.path)?; + let content = utils::read_locked_file("settings", &self.path)?; Settings::parse(&content).with_context(|| RustupError::ParsingFile { name: "settings", path: self.path.clone(), diff --git a/src/utils/mod.rs b/src/utils/mod.rs index fdb079ccaf..414a5687a4 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -87,6 +87,13 @@ pub fn read_file(name: &'static str, path: &Path) -> Result { }) } +pub(crate) fn read_locked_file(name: &'static str, path: &Path) -> Result { + raw::read_locked_file(path).with_context(|| RustupError::ReadingFile { + name, + path: PathBuf::from(path), + }) +} + pub fn write_file(name: &'static str, path: &Path, contents: &str) -> Result<()> { raw::write_file(path, contents).with_context(|| RustupError::WritingFile { name, @@ -94,6 +101,13 @@ pub fn write_file(name: &'static str, path: &Path, contents: &str) -> Result<()> }) } +pub(crate) fn write_locked_file(name: &'static str, path: &Path, contents: &str) -> Result<()> { + raw::write_locked_file(path, contents).with_context(|| RustupError::WritingFile { + name, + path: PathBuf::from(path), + }) +} + pub(crate) fn append_file(name: &'static str, path: &Path, line: &str) -> Result<()> { raw::append_file(path, line).with_context(|| RustupError::WritingFile { name, diff --git a/src/utils/raw.rs b/src/utils/raw.rs index ba439ae731..70f27f3d42 100644 --- a/src/utils/raw.rs +++ b/src/utils/raw.rs @@ -3,7 +3,7 @@ use std::env; use std::fs; use std::fs::File; use std::io; -use std::io::Write; +use std::io::{Read, Seek, SeekFrom, Write}; use std::path::Path; use std::str; @@ -60,6 +60,21 @@ pub fn path_exists>(path: P) -> bool { fs::metadata(path).is_ok() } +pub(crate) fn read_locked_file(path: &Path) -> io::Result { + let mut file = File::open(path)?; + file.lock_shared()?; + + let size = file + .metadata() + .map(|metadata| usize::try_from(metadata.len()).unwrap_or(usize::MAX)) + .ok(); + let mut contents = String::new(); + contents.try_reserve_exact(size.unwrap_or(0))?; + file.read_to_string(&mut contents)?; + + Ok(contents) +} + pub(crate) fn random_string(length: usize) -> String { const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz0123456789_"; let mut rng = rand::rng(); @@ -82,6 +97,24 @@ pub fn write_file(path: &Path, contents: &str) -> io::Result<()> { Ok(()) } +pub(crate) fn write_locked_file(path: &Path, contents: &str) -> io::Result<()> { + let mut file = fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + // Truncation must happen after the exclusive lock is held. + .truncate(false) + .open(path)?; + + file.lock()?; + file.set_len(0)?; + file.seek(SeekFrom::Start(0))?; + Write::write_all(&mut file, contents.as_bytes())?; + file.sync_data()?; + + Ok(()) +} + pub(crate) fn filter_file bool>( src: &Path, dest: &Path, @@ -350,3 +383,20 @@ pub(crate) mod windows { inner(s.as_ref()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn locked_file_round_trip_truncates_previous_contents() -> io::Result<()> { + let temp_dir = tempfile::tempdir()?; + let path = temp_dir.path().join("state.toml"); + + write_locked_file(&path, "last_release_notified_secs = 123456\n")?; + write_locked_file(&path, "version = \"12\"\n")?; + + assert_eq!(read_locked_file(&path)?, "version = \"12\"\n"); + Ok(()) + } +} From 414cd98c1ada6d04259ce0a6d31ffebdeb439571 Mon Sep 17 00:00:00 2001 From: rami3l Date: Fri, 10 Jul 2026 16:31:13 +0200 Subject: [PATCH 06/18] refactor: replace `cfg_if!{}` with `cfg_select!{}` --- Cargo.lock | 1 - Cargo.toml | 1 - src/bin/rustup-init.rs | 10 +++------- src/cli/self_update.rs | 10 +++------- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8b130acadd..4079b4598c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2083,7 +2083,6 @@ dependencies = [ "anstyle", "anyhow", "cc", - "cfg-if 1.0.4", "chrono", "clap", "clap-cargo", diff --git a/Cargo.toml b/Cargo.toml index f948012b20..ef536cb016 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,6 @@ anstream = "1" anstyle = "1.0.11" anyhow = "1.0.69" cc = "1" -cfg-if = "1.0" chrono = { version = "0.4", default-features = false, features = ["std"] } clap = { version = "4", features = ["derive", "wrap_help", "string"] } clap-cargo = "0.18.3" diff --git a/src/bin/rustup-init.rs b/src/bin/rustup-init.rs index e844ddc19e..a0d408abc8 100644 --- a/src/bin/rustup-init.rs +++ b/src/bin/rustup-init.rs @@ -16,7 +16,6 @@ use std::process::ExitCode; use anyhow::{Context, Result, anyhow}; -use cfg_if::cfg_if; // Public macros require availability of the internal symbols use rs_tracing::{ close_trace_file, close_trace_file_internal, open_trace_file, trace_to_file_internal, @@ -105,12 +104,9 @@ async fn run_rustup_inner( Some(n) if n.starts_with("rustup-gc-") => { // This is the final uninstallation stage on windows where // rustup deletes its own exe - cfg_if! { - if #[cfg(windows)] { - self_update::complete_windows_uninstall(process) - } else { - unreachable!("Attempted to use Windows-specific code on a non-Windows platform. Aborting.") - } + cfg_select! { + windows => self_update::complete_windows_uninstall(process), + _ => unreachable!("Attempted to use Windows-specific code on a non-Windows platform. Aborting."), } } Some(n) => { diff --git a/src/cli/self_update.rs b/src/cli/self_update.rs index 96fc010553..374464b86d 100644 --- a/src/cli/self_update.rs +++ b/src/cli/self_update.rs @@ -42,7 +42,6 @@ use std::{fmt, fs}; use anstyle::Style; use anyhow::{Context, Result, anyhow}; -use cfg_if::cfg_if; use clap::ValueEnum; use clap::builder::PossibleValue; use clap_cargo::style::{GOOD, WARN}; @@ -539,12 +538,9 @@ fn canonical_cargo_home(process: &Process) -> Result> { .unwrap_or_else(|| PathBuf::from(".")) .join(".cargo"); Ok(if default_cargo_home == path { - cfg_if! { - if #[cfg(windows)] { - r"%USERPROFILE%\.cargo".into() - } else { - "$HOME/.cargo".into() - } + cfg_select! { + windows => r"%USERPROFILE%\.cargo".into(), + _ => "$HOME/.cargo".into(), } } else { path.to_string_lossy().into_owned().into() From 05e269e41984a8435e0122e934b629318b6b0743 Mon Sep 17 00:00:00 2001 From: rami3l Date: Fri, 10 Jul 2026 17:09:33 +0200 Subject: [PATCH 07/18] chore(deps): remove pinned `openssl-src` The underlying issue has been resolved in OpenSSL v3.6.3: https://github.com/openssl/openssl/commit/7936b4c415ae0d27162bf2c6ef9a96d1e5ffb5a9 --- Cargo.lock | 7 +++---- Cargo.toml | 3 --- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4079b4598c..0b65057f60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1515,9 +1515,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-src" -version = "300.5.4+3.5.4" +version = "300.6.1+3.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" +checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" dependencies = [ "cc", ] @@ -2107,7 +2107,6 @@ dependencies = [ "libz-sys", "opener", "openssl", - "openssl-src", "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", @@ -2459,7 +2458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.3", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys 0.52.0", diff --git a/Cargo.toml b/Cargo.toml index ef536cb016..5da4af936f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,9 +67,6 @@ opener = "0.8.0" # `openssl` is used by `curl` or `reqwest` backend although it isn't imported by rustup: this # allows controlling the vendoring status without exposing the presence of the download crate. openssl = { version = "0.10", optional = true } -# HACK: Temporarily pinned due to ppc64 ELFv1/v2 ABI issue in 300.5.5, to be -# removed when lands. -openssl-src = { version = "=300.5.4", optional = true } opentelemetry = { version = "0.32", optional = true } opentelemetry-otlp = { version = "0.32", features = ["grpc-tonic"], optional = true } opentelemetry_sdk = { version = "0.32", features = ["rt-tokio"], optional = true } From e8671e705e772d98ad7d4058d0f852f7a4657d75 Mon Sep 17 00:00:00 2001 From: rami3l Date: Mon, 13 Jul 2026 09:35:24 +0200 Subject: [PATCH 08/18] chore(deps): bump `platforms` to 4.1.0 --- Cargo.lock | 4 ++-- src/dist/target_tuple/known.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b65057f60..af5443e767 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1652,9 +1652,9 @@ checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "platforms" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1edb60d9efe54a87684d4d6217f612ecd22976ec9220e3e3ad78df2deeefc31" +checksum = "acff5dfd42135d89cd7ad74a8c52813bbec91bf62c018ddd89390127767caab5" [[package]] name = "portable-atomic" diff --git a/src/dist/target_tuple/known.rs b/src/dist/target_tuple/known.rs index fbcf35f455..6f46fbfb02 100644 --- a/src/dist/target_tuple/known.rs +++ b/src/dist/target_tuple/known.rs @@ -54,6 +54,7 @@ pub static LIST_ARCHS: &[&str] = &[ "riscv32imac", "riscv32imafc", "riscv32imc", + "riscv32imfc", "riscv64", "riscv64a23", "riscv64gc", From cf7e010a1a1c249f7451c56ac7e8020a72f100f7 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 13 Jul 2026 01:01:47 +0000 Subject: [PATCH 09/18] chore(deps): lock file maintenance --- Cargo.lock | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af5443e767..bcb983916e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -232,15 +232,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.2.66" +version = "1.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" dependencies = [ "find-msvc-tools", "jobserver", @@ -1350,9 +1350,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "miniz_oxide" @@ -1606,7 +1606,7 @@ dependencies = [ "opentelemetry", "percent-encoding", "portable-atomic", - "rand 0.9.4", + "rand 0.9.5", "thiserror 2.0.18", "tokio", "tokio-stream", @@ -1705,7 +1705,7 @@ dependencies = [ "bit-vec", "bitflags", "num-traits", - "rand 0.9.4", + "rand 0.9.5", "rand_chacha", "rand_xorshift", "regex-syntax", @@ -1786,9 +1786,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ "rand_chacha", "rand_core 0.9.5", @@ -1861,9 +1861,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.4" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" dependencies = [ "aho-corasick", "memchr", @@ -1873,9 +1873,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" dependencies = [ "aho-corasick", "memchr", @@ -1951,7 +1951,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1cab9bd343c737660e523ee69f788018f3db686d537d2fd0f99c9f747c1bda4f" dependencies = [ - "rand 0.9.4", + "rand 0.9.5", ] [[package]] @@ -2458,7 +2458,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.52.0", @@ -2516,9 +2516,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if 1.0.4", ] @@ -3314,18 +3314,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.53" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75726053136156d419e285b9b7eddaaea9e3fea6ce32eed44a89901f0bd98de1" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.53" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4714fd92cf900833d49538023a9b3915155210801d1c1169eba513b2addefd71" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", @@ -3394,15 +3394,15 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5" +checksum = "b142a20ec14a91d5bc708c1dc21b080c550113d8aa77afa29635673a65dd02c5" [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "bd2f034a4bebf216c9e4b7083603e024cf930873fd67830cfb083c9fa33129d9" [[package]] name = "zstd" From c6f028a0f26d4fd34fa9c4f06c6fa0c9197ba03c Mon Sep 17 00:00:00 2001 From: Akrm Al-Hakimi Date: Mon, 13 Jul 2026 09:23:53 -0400 Subject: [PATCH 10/18] fix(self-update): only remove complete profile lines --- src/cli/self_update/unix.rs | 20 ++++++++++++-------- tests/suite/cli_paths.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/cli/self_update/unix.rs b/src/cli/self_update/unix.rs index e4e236e2bc..b063f2c462 100644 --- a/src/cli/self_update/unix.rs +++ b/src/cli/self_update/unix.rs @@ -61,10 +61,7 @@ pub(crate) fn do_remove_from_path(process: &Process) -> Result<()> { let file = utils::read_file("rcfile", rc)?; let file_bytes = file.into_bytes(); // FIXME: This is whitespace sensitive where it should not be. - if let Some(idx) = file_bytes - .windows(source_bytes.len()) - .position(|w| w == source_bytes.as_slice()) - { + if let Some(idx) = find_exact_line(&file_bytes, &source_bytes) { // Here we rewrite the file without the offending line. let mut new_bytes = file_bytes[..idx].to_vec(); new_bytes.extend(&file_bytes[idx + source_bytes.len()..]); @@ -153,10 +150,7 @@ fn remove_legacy_source_command(source_cmd: String, process: &Process) -> Result let file = utils::read_file("rcfile", &rc)?; let file_bytes = file.into_bytes(); // FIXME: This is whitespace sensitive where it should not be. - if let Some(idx) = file_bytes - .windows(cmd_bytes.len()) - .position(|w| w == cmd_bytes.as_slice()) - { + if let Some(idx) = find_exact_line(&file_bytes, &cmd_bytes) { // Here we rewrite the file without the offending line. let mut new_bytes = file_bytes[..idx].to_vec(); new_bytes.extend(&file_bytes[idx + cmd_bytes.len()..]); @@ -167,6 +161,16 @@ fn remove_legacy_source_command(source_cmd: String, process: &Process) -> Result Ok(()) } +fn find_exact_line(file: &[u8], line: &[u8]) -> Option { + // The trailing newline enforces the end boundary; check the start boundary here. + assert!(line.ends_with(b"\n")); + file.windows(line.len()) + .enumerate() + .find_map(|(idx, candidate)| { + (candidate == line && (idx == 0 || file[idx - 1] == b'\n')).then_some(idx) + }) +} + fn remove_legacy_paths(process: &Process) -> Result<()> { // Before the work to support more kinds of shells, which was released in // version 1.23.0 of Rustup, we always inserted this line instead, which is diff --git a/tests/suite/cli_paths.rs b/tests/suite/cli_paths.rs index f102dd5234..f530619526 100644 --- a/tests/suite/cli_paths.rs +++ b/tests/suite/cli_paths.rs @@ -348,6 +348,41 @@ error: could not amend shell profile[..] } } + #[tokio::test] + async fn install_preserves_guarded_legacy_source() { + let cx = CliTestContext::new(Scenario::Empty).await; + let profile = cx.config.homedir.join(".bash_profile"); + let guarded_source = "[ -f \"$HOME/.cargo/env\" ] && source \"$HOME/.cargo/env\"\n"; + raw::write_file(&profile, guarded_source).unwrap(); + + let mut cmd = cx.config.cmd("rustup-init", &INIT_NONE[1..]); + cmd.env_remove("CARGO_HOME"); + assert!(cmd.output().unwrap().status.success()); + + let new_profile = fs::read_to_string(&profile).unwrap(); + let expected = guarded_source.to_owned() + &source("$HOME/.cargo", POSIX_SH); + assert_eq!(new_profile, expected); + } + + #[tokio::test] + async fn uninstall_preserves_guarded_source() { + let cx = CliTestContext::new(Scenario::Empty).await; + let profile = cx.config.homedir.join(".bash_profile"); + let guarded_source = "[ -f \"$HOME/.cargo/env\" ] && . \"$HOME/.cargo/env\"\n"; + raw::write_file(&profile, guarded_source).unwrap(); + + let mut cmd = cx.config.cmd("rustup-init", &INIT_NONE[1..]); + cmd.env_remove("CARGO_HOME"); + assert!(cmd.output().unwrap().status.success()); + + let mut cmd = cx.config.cmd("rustup", ["self", "uninstall", "-y"]); + cmd.env_remove("CARGO_HOME"); + assert!(cmd.output().unwrap().status.success()); + + let new_profile = fs::read_to_string(&profile).unwrap(); + assert_eq!(new_profile, guarded_source); + } + #[tokio::test] async fn uninstall_cleans_up_legacy_paths() { let cx = CliTestContext::new(Scenario::Empty).await; From 6fc81d9db8f6c9456a5efb4d29e49be0d290f1b0 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 14 Jul 2026 10:13:40 +0000 Subject: [PATCH 11/18] Docs: Remove i686 `set default-host` example --- doc/user-guide/src/installation/windows.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/doc/user-guide/src/installation/windows.md b/doc/user-guide/src/installation/windows.md index 59ac3bde82..b9d5d52c40 100644 --- a/doc/user-guide/src/installation/windows.md +++ b/doc/user-guide/src/installation/windows.md @@ -25,13 +25,7 @@ target that tuple by default. You can change this behavior with `rustup set default-host` or during installation. -For example, to explicitly select the 32-bit MSVC host: - -```console -$ rustup set default-host i686-pc-windows-msvc -``` - -Or to choose the 64 bit GNU toolchain: +For example, to choose the 64 bit GNU toolchain: ```console $ rustup set default-host x86_64-pc-windows-gnu From 634d45d8f26116cfe2dad13947db56522f82137e Mon Sep 17 00:00:00 2001 From: ychampion Date: Tue, 14 Jul 2026 14:30:55 +0000 Subject: [PATCH 12/18] refactor: expose the installed manifest path --- src/dist/manifestation.rs | 6 ++---- src/dist/prefix.rs | 6 ++++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/dist/manifestation.rs b/src/dist/manifestation.rs index 469d830910..9bb2467e52 100644 --- a/src/dist/manifestation.rs +++ b/src/dist/manifestation.rs @@ -29,14 +29,13 @@ use crate::{ config::Config, download::{DownloadCfg, DownloadStatus, File}, manifest::{Component, CompressionKind, HashedBinary, Manifest}, - prefix::InstallPrefix, + prefix::{DIST_MANIFEST, InstallPrefix}, temp, }, errors::RustupError, utils, }; -pub(crate) const DIST_MANIFEST: &str = "multirust-channel-manifest.toml"; pub(crate) const CONFIG_FILE: &str = "multirust-config.toml"; #[derive(Debug)] @@ -396,8 +395,7 @@ impl Manifestation { #[tracing::instrument(level = "trace")] pub fn load_manifest(&self) -> Result> { let prefix = self.installation.prefix(); - let old_manifest_path = prefix.manifest_file(DIST_MANIFEST); - if utils::path_exists(&old_manifest_path) { + if let Some(old_manifest_path) = prefix.dist_manifest() { let manifest_str = utils::read_file("installed manifest", &old_manifest_path)?; Ok(Some(Manifest::parse(&manifest_str).with_context(|| { RustupError::ParsingFile { diff --git a/src/dist/prefix.rs b/src/dist/prefix.rs index 9b71118017..c0217bfb86 100644 --- a/src/dist/prefix.rs +++ b/src/dist/prefix.rs @@ -11,6 +11,7 @@ const REL_MANIFEST_DIR: &str = match std::path::MAIN_SEPARATOR { }; static V1_COMMON_COMPONENT_LIST: &[&str] = &["cargo", "rustc", "rust-docs"]; +pub(crate) const DIST_MANIFEST: &str = "multirust-channel-manifest.toml"; #[derive(Clone, Debug)] pub struct InstallPrefix { @@ -37,6 +38,11 @@ impl InstallPrefix { path } + pub(crate) fn dist_manifest(&self) -> Option { + let path = self.manifest_file(DIST_MANIFEST); + utils::path_exists(&path).then_some(path) + } + pub(crate) fn rel_manifest_file(&self, name: &str) -> PathBuf { let mut path = PathBuf::from(REL_MANIFEST_DIR); path.push(name); From 2d16135c40c0b9fb9ccd9b2dd5a06a5b62cde6a9 Mon Sep 17 00:00:00 2001 From: ychampion Date: Tue, 14 Jul 2026 14:30:55 +0000 Subject: [PATCH 13/18] fix: repair toolchains without an installed manifest --- src/dist/mod.rs | 7 ++--- src/toolchain/distributable.rs | 12 ++++--- tests/suite/cli_rustup.rs | 57 +++++++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/dist/mod.rs b/src/dist/mod.rs index d74afa014c..dc95784dbd 100644 --- a/src/dist/mod.rs +++ b/src/dist/mod.rs @@ -1125,10 +1125,9 @@ async fn try_update_from_dist_( } else { download .dl_v2_manifest( - // Even if manifest has not changed, we must continue to install requested components. - // So if components or targets is not empty, we skip passing `update_hash` so that - // we essentially degenerate to `rustup component add` / `rustup target add` - if components.is_empty() && targets.is_empty() { + // Skip the update hash when the installed manifest is missing or when components + // or targets were requested, since either case still requires the channel manifest. + if prefix.dist_manifest().is_some() && components.is_empty() && targets.is_empty() { Some(update_hash) } else { None diff --git a/src/toolchain/distributable.rs b/src/toolchain/distributable.rs index a76776fa07..96dfe265d2 100644 --- a/src/toolchain/distributable.rs +++ b/src/toolchain/distributable.rs @@ -439,12 +439,14 @@ impl<'a> DistributableToolchain<'a> { } pub async fn fetch_dist_manifest(&self) -> anyhow::Result> { + let prefix = InstallPrefix::from(self.toolchain.path()); + let update_hash = if prefix.dist_manifest().is_some() { + Some(self.toolchain.cfg.get_hash_file(&self.desc, false)?) + } else { + None + }; DownloadCfg::new(self.toolchain.cfg) - .dl_v2_manifest( - Some(&self.toolchain.cfg.get_hash_file(&self.desc, false)?), - &self.desc, - self.toolchain.cfg, - ) + .dl_v2_manifest(update_hash.as_deref(), &self.desc, self.toolchain.cfg) .await } diff --git a/tests/suite/cli_rustup.rs b/tests/suite/cli_rustup.rs index 3b2dc1889c..76ca060212 100644 --- a/tests/suite/cli_rustup.rs +++ b/tests/suite/cli_rustup.rs @@ -4173,14 +4173,7 @@ async fn missing_manifest_shows_reinstall_help() { .await .is_ok(); - let manifest_path = cx - .config - .rustupdir - .join("toolchains") - .join(format!("nightly-{}", this_host_tuple())) - .join("lib") - .join("rustlib") - .join("multirust-channel-manifest.toml"); + let manifest_path = nightly_manifest_path(&cx); fs::remove_file(&manifest_path).unwrap(); @@ -4195,3 +4188,51 @@ help: try reinstalling or updating the toolchain "#]]) .is_err(); } + +#[tokio::test] +async fn reinstall_restores_missing_manifest() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + + cx.config + .expect(["rustup", "toolchain", "install", "nightly"]) + .await + .is_ok(); + + let manifest_path = nightly_manifest_path(&cx); + + fs::remove_file(&manifest_path).unwrap(); + + cx.config + .expect(["rustup", "toolchain", "install", "nightly"]) + .await + .is_ok(); + + assert!(manifest_path.exists()); +} + +#[tokio::test] +async fn update_all_restores_missing_manifest() { + let cx = CliTestContext::new(Scenario::SimpleV2).await; + + cx.config + .expect(["rustup", "toolchain", "install", "nightly"]) + .await + .is_ok(); + + let manifest_path = nightly_manifest_path(&cx); + fs::remove_file(&manifest_path).unwrap(); + + cx.config.expect(["rustup", "update"]).await.is_ok(); + + assert!(manifest_path.exists()); +} + +fn nightly_manifest_path(cx: &CliTestContext) -> PathBuf { + cx.config + .rustupdir + .join("toolchains") + .join(format!("nightly-{}", this_host_tuple())) + .join("lib") + .join("rustlib") + .join("multirust-channel-manifest.toml") +} From c04fe2b5e6ef5872754ca5de559143972b691a3b Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Thu, 9 Jul 2026 15:38:29 +0200 Subject: [PATCH 14/18] Add Enzyme to the list of rustup components --- doc/user-guide/src/concepts/components.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/user-guide/src/concepts/components.md b/doc/user-guide/src/concepts/components.md index 2d9b74beeb..9dce622a9c 100644 --- a/doc/user-guide/src/concepts/components.md +++ b/doc/user-guide/src/concepts/components.md @@ -62,6 +62,8 @@ toolchains. The following is an overview of the different components: * `rustc-dev` --- This component contains the compiler as a library. Most users will not need this; it is only needed for development *of* tools that link to the compiler, such as making modifications to [Clippy]. +* `enzyme` --- This component enables the `std::autodiff` module in nightly Rust. + See [autodiff][enzyme] for more detail. ### Previous components @@ -101,3 +103,4 @@ details. [rustup components history]: https://rust-lang.github.io/rustup-components-history/ [profiles]: profiles.md [nightly availability]: channels.md#nightly-availability +[enzyme]: https://rustc-dev-guide.rust-lang.org/autodiff/installation.html From 98123afc491f83111b753bc9880073bd2e397494 Mon Sep 17 00:00:00 2001 From: Francisco Gouveia Date: Wed, 15 Jul 2026 11:14:54 +0100 Subject: [PATCH 15/18] fix(toolchain): inline use of `set_override` --- src/cli/rustup_mode.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 57e267ffcc..5b3febd214 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -1040,7 +1040,6 @@ async fn update( let self_update_mode = SelfUpdateMode::from_cfg(cfg)?; let should_self_update = !opts.no_self_update; let force_non_host = opts.force_non_host; - let set_override = opts.r#override; cfg.profile_override = opts.profile; let cfg = &cfg; @@ -1099,7 +1098,7 @@ async fn update( Ok(status.clone()), )?; - if set_override { + if opts.r#override { cfg.make_override(&cfg.current_dir, &desc.clone().into())?; } From a262e615e2bf608b3cc839a65ef58d26c4796731 Mon Sep 17 00:00:00 2001 From: Francisco Gouveia Date: Wed, 15 Jul 2026 10:25:30 +0100 Subject: [PATCH 16/18] feat(toolchain): add `--default` flag to `rustup toolchain install` --- src/cli/rustup_mode.rs | 8 +++++- ..._cmd_install_cmd_help_flag.stdout.term.svg | 28 ++++++++++--------- tests/suite/cli_v2.rs | 21 ++++++++++++++ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/cli/rustup_mode.rs b/src/cli/rustup_mode.rs index 5b3febd214..3dfaa3fc6f 100644 --- a/src/cli/rustup_mode.rs +++ b/src/cli/rustup_mode.rs @@ -468,6 +468,10 @@ struct UpdateOpts { /// Set the installed toolchain as the override for the current directory #[arg(long)] r#override: bool, + + /// Set the installed toolchain as the default toolchain + #[arg(long)] + default: bool, } #[derive(Debug, Default, Args)] @@ -1102,7 +1106,9 @@ async fn update( cfg.make_override(&cfg.current_dir, &desc.clone().into())?; } - if cfg.get_default()?.is_none() && matches!(status, UpdateStatus::Installed) { + if opts.default + || (cfg.get_default()?.is_none() && matches!(status, UpdateStatus::Installed)) + { cfg.set_default(Some(&desc.into()))?; } } diff --git a/tests/suite/cli_rustup_ui/rustup_toolchain_cmd_install_cmd_help_flag.stdout.term.svg b/tests/suite/cli_rustup_ui/rustup_toolchain_cmd_install_cmd_help_flag.stdout.term.svg index f996dc9902..d42f1d8930 100644 --- a/tests/suite/cli_rustup_ui/rustup_toolchain_cmd_install_cmd_help_flag.stdout.term.svg +++ b/tests/suite/cli_rustup_ui/rustup_toolchain_cmd_install_cmd_help_flag.stdout.term.svg @@ -1,4 +1,4 @@ - +