From 10b6c5f5a72ad95bcad6325ca95fca91460f8bfa Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 26 Sep 2025 15:01:01 +0100 Subject: [PATCH 1/9] Move -Cembed-bitcode --- library/Cargo.toml | 18 ++++++++++++ src/bootstrap/src/core/build_steps/compile.rs | 7 ----- src/bootstrap/src/core/build_steps/dist.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 5 ++-- src/bootstrap/src/core/builder/cargo.rs | 29 ++++++++++++++----- src/bootstrap/src/lib.rs | 10 +++++-- 6 files changed, 50 insertions(+), 21 deletions(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index e30e624094285..2b664ec9bc825 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -54,6 +54,24 @@ rustflags = ["-Cpanic=abort"] [profile.release.package.panic_abort] rustflags = ["-Cpanic=abort"] +# The "dist" profile is used by bootstrap for prebuilt libstd artifacts +# These settings ensure that the prebuilt artifacts support a variety of features +# in the user's profile. +[profile.dist] +inherits = "release" +rustflags = [ + # Unconditionally embedding bitcode is necessary for when users enable LTO. + # Until Cargo can rebuild the standard library with the user profile's `lto` + # setting, Cargo will force this to be `no` + "-Cembed-bitcode=yes", +] + +[profile.dist.package.panic_abort] +rustflags = [ + "-Cpanic=abort", + "-Cembed-bitcode=yes", +] + [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on here rustc-std-workspace-core = { path = 'rustc-std-workspace-core' } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 651ff03a8690a..2ea4bf96c86d9 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -680,13 +680,6 @@ pub fn std_cargo( } } - // By default, rustc uses `-Cembed-bitcode=yes`, and Cargo overrides that - // with `-Cembed-bitcode=no` for non-LTO builds. However, libstd must be - // built with bitcode so that the produced rlibs can be used for both LTO - // builds (which use bitcode) and non-LTO builds (which use object code). - // So we override the override here! - cargo.rustflag("-Cembed-bitcode=yes"); - if builder.config.rust_lto == RustcLto::Off { cargo.rustflag("-Clto=off"); } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 8ba05a7fa3a7f..84ab15781cdd6 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1008,7 +1008,7 @@ impl Step for Analysis { let src = builder .stage_out(compiler, Mode::Std) .join(target) - .join(builder.cargo_dir()) + .join(builder.cargo_dir(Mode::Std)) .join("deps") .join("save-analysis"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index f3a1c6b0e3dde..786c08cce17ac 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -927,8 +927,9 @@ impl Step for Clippy { cargo.env("RUSTC_TEST_SUITE", builder.rustc(build_compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(build_compiler)); - let host_libs = - builder.stage_out(build_compiler, Mode::ToolRustcPrivate).join(builder.cargo_dir()); + let host_libs = builder + .stage_out(build_compiler, Mode::ToolRustcPrivate) + .join(builder.cargo_dir(Mode::ToolRustcPrivate)); cargo.env("HOST_LIBS", host_libs); // Build the standard library that the tests can use. diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index dda0b40cb69eb..6acffc1bf2c1d 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -106,9 +106,9 @@ pub struct Cargo { rustdocflags: Rustflags, hostflags: HostFlags, allow_features: String, - release_build: bool, build_compiler_stage: u32, extra_rustflags: Vec, + profile: Option<&'static str>, } impl Cargo { @@ -137,7 +137,11 @@ impl Cargo { } pub fn release_build(&mut self, release_build: bool) { - self.release_build = release_build; + self.profile = if release_build { Some("release") } else { None }; + } + + pub fn profile(&mut self, profile: &'static str) { + self.profile = Some(profile); } pub fn compiler(&self) -> Compiler { @@ -407,8 +411,8 @@ impl Cargo { impl From for BootstrapCommand { fn from(mut cargo: Cargo) -> BootstrapCommand { - if cargo.release_build { - cargo.args.insert(0, "--release".into()); + if let Some(profile) = cargo.profile { + cargo.args.insert(0, format!("--profile={profile}").into()); } for arg in &cargo.extra_rustflags { @@ -1434,9 +1438,18 @@ impl Builder<'_> { .unwrap_or(&self.config.rust_rustflags) .clone(); - let release_build = 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); + let profile = + if matches!(cmd_kind, Kind::Bench | Kind::Miri | Kind::MiriSetup | Kind::MiriTest) { + // Use the default profile for bench/miri + None + } else { + match (mode, self.config.rust_optimize.is_release()) { + // Some std configuration exists in its own profile + (Mode::Std, true) => Some("dist"), + (_, true) => Some("release"), + (_, false) => Some("dev"), + } + }; Cargo { command: cargo, @@ -1448,9 +1461,9 @@ impl Builder<'_> { rustdocflags, hostflags, allow_features, - release_build, build_compiler_stage, extra_rustflags, + profile, } } } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 857c0539e7d27..7af96bca44bdf 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -898,8 +898,12 @@ impl Build { /// Component directory that Cargo will produce output into (e.g. /// release/debug) - fn cargo_dir(&self) -> &'static str { - if self.config.rust_optimize.is_release() { "release" } else { "debug" } + fn cargo_dir(&self, mode: Mode) -> &'static str { + match (mode, self.config.rust_optimize.is_release()) { + (Mode::Std, true) => "dist", + (_, true) => "release", + (_, false) => "debug", + } } fn tools_dir(&self, build_compiler: Compiler) -> PathBuf { @@ -956,7 +960,7 @@ impl Build { /// running a particular compiler, whether or not we're building the /// standard library, and targeting the specified architecture. fn cargo_out(&self, build_compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf { - self.stage_out(build_compiler, mode).join(target).join(self.cargo_dir()) + self.stage_out(build_compiler, mode).join(target).join(self.cargo_dir(mode)) } /// Root output directory of LLVM for `target` From 95c9586463937a9b5141ba7b7e6202af407c2a39 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 26 Sep 2025 15:24:44 +0100 Subject: [PATCH 2/9] Move frame pointers --- library/Cargo.toml | 5 +++++ src/bootstrap/src/core/build_steps/compile.rs | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index 2b664ec9bc825..a1f64a4a32373 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -64,12 +64,17 @@ rustflags = [ # Until Cargo can rebuild the standard library with the user profile's `lto` # setting, Cargo will force this to be `no` "-Cembed-bitcode=yes", + # Enable frame pointers + "-Zunstable-options", + "-Cforce-frame-pointers=non-leaf", ] [profile.dist.package.panic_abort] rustflags = [ "-Cpanic=abort", "-Cembed-bitcode=yes", + "-Zunstable-options", + "-Cforce-frame-pointers=non-leaf", ] [patch.crates-io] diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 2ea4bf96c86d9..7107140e15110 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -694,11 +694,6 @@ pub fn std_cargo( cargo.rustflag("-Cforce-unwind-tables=yes"); } - // Enable frame pointers by default for the library. Note that they are still controlled by a - // separate setting for the compiler. - cargo.rustflag("-Zunstable-options"); - cargo.rustflag("-Cforce-frame-pointers=non-leaf"); - let html_root = format!("-Zcrate-attr=doc(html_root_url=\"{}/\")", builder.doc_rust_lang_org_channel(),); cargo.rustflag(&html_root); From cabaed495acd6c968496fd4e0a72543b29ebbdad Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 30 Sep 2025 13:51:11 +0100 Subject: [PATCH 3/9] Move debuginfo=1 --- library/Cargo.toml | 2 ++ src/ci/run.sh | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index a1f64a4a32373..2a2c015811b8e 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -59,6 +59,8 @@ rustflags = ["-Cpanic=abort"] # in the user's profile. [profile.dist] inherits = "release" +codegen-units = 1 +debug = 1 # "limited" rustflags = [ # Unconditionally embedding bitcode is necessary for when users enable LTO. # Until Cargo can rebuild the standard library with the user profile's `lto` diff --git a/src/ci/run.sh b/src/ci/run.sh index b486f0525f40d..583ad4461bc3f 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -120,8 +120,6 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then if [ "$DEPLOY_ALT" != "" ] && isLinux; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level=2" - else - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" fi if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then From 1155a30c0e05dc8ed17f0466b655f46cd4d1d82d Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Tue, 30 Sep 2025 17:13:07 +0100 Subject: [PATCH 4/9] Move symbol mangling --- src/bootstrap/src/core/builder/cargo.rs | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 6acffc1bf2c1d..041217e1dc8ca 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -664,23 +664,15 @@ impl Builder<'_> { 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 - } - // Per compiler-team#938, v0 mangling is used on nightly - None if self.config.channel == "dev" || self.config.channel == "nightly" => true, - 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 - } + let use_new_symbol_mangling = self.config.rust_new_symbol_mangling.or_else(|| { + if mode != Mode::Std { + // The compiler and tools default to the new scheme + Some(true) + } else { + // std follows the flag's default, which per compiler-team#938 is v0 on nightly + None } - }; + }); // 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 @@ -691,11 +683,11 @@ impl Builder<'_> { rustflags.arg("--cfg=windows_raw_dylib"); } - if use_new_symbol_mangling { - rustflags.arg("-Csymbol-mangling-version=v0"); - } else { - rustflags.arg("-Csymbol-mangling-version=legacy"); - } + rustflags.arg(match use_new_symbol_mangling { + Some(true) => "-Csymbol-mangling-version=v0", + Some(false) => "-Csymbol-mangling-version=legacy", + None => "", + }); // Always enable move/copy annotations for profiler visibility (non-stage0 only). // Note that -Zannotate-moves is only effective with debugging info enabled. From dae8ea92a7337b3c2c4db7d06de554fbcf2de2e8 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Mon, 6 Oct 2025 16:53:54 +0100 Subject: [PATCH 5/9] Configure test's unstable feature gate when built outside of bootstrap This uses a build probe to figure out the current toolchain version - the only alternative to this is bespoke logic in Cargo to tell `test` when the toolchain is stable/unstable. The behaviour should be the same as when using `CFG_DISABLE_UNSTABLE_FEATURES` unless an arbitrary channel is provided to bootstrap, which I believe necessitates a fork anyway. --- library/test/build.rs | 11 +++++++++++ library/test/src/cli.rs | 11 +++++------ src/bootstrap/src/core/build_steps/compile.rs | 6 ------ 3 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 library/test/build.rs diff --git a/library/test/build.rs b/library/test/build.rs new file mode 100644 index 0000000000000..a2bc8936b5195 --- /dev/null +++ b/library/test/build.rs @@ -0,0 +1,11 @@ +fn main() { + println!("cargo:rustc-check-cfg=cfg(enable_unstable_features)"); + + let rustc = std::env::var("RUSTC").unwrap_or_else(|_| "rustc".into()); + let version = std::process::Command::new(rustc).arg("-vV").output().unwrap(); + let stdout = String::from_utf8(version.stdout).unwrap(); + + if stdout.contains("nightly") || stdout.contains("dev") { + println!("cargo:rustc-cfg=enable_unstable_features"); + } +} diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 35291cc15c918..172785936b207 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -314,15 +314,14 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { Ok(test_opts) } -// FIXME: Copied from librustc_ast until linkage errors are resolved. Issue #47566 fn is_nightly() -> bool { - // Whether this is a feature-staged build, i.e., on the beta or stable channel - let disable_unstable_features = - option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false); - // Whether we should enable unstable features for bootstrapping + // Whether the current rustc version should allow unstable features + let enable_unstable_features = cfg!(enable_unstable_features); + + // The runtime override for unstable features let bootstrap = env::var("RUSTC_BOOTSTRAP").is_ok(); - bootstrap || !disable_unstable_features + bootstrap || enable_unstable_features } // Gets the CLI options associated with `report-time` feature. diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 7107140e15110..405ab9f6eaa2d 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -626,12 +626,6 @@ pub fn std_cargo( CompilerBuiltins::BuildRustOnly => "", }; - // `libtest` uses this to know whether or not to support - // `-Zunstable-options`. - if !builder.unstable_features() { - cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); - } - for krate in crates { cargo.args(["-p", krate]); } From 539a045dfbf846692c8539e42a1d98efefa2fae9 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 8 Jan 2026 16:22:26 +0000 Subject: [PATCH 6/9] Rephrase embed-bitcode comment --- library/Cargo.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/Cargo.toml b/library/Cargo.toml index 2a2c015811b8e..b26e5f41c9313 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -62,9 +62,10 @@ inherits = "release" codegen-units = 1 debug = 1 # "limited" rustflags = [ - # Unconditionally embedding bitcode is necessary for when users enable LTO. - # Until Cargo can rebuild the standard library with the user profile's `lto` - # setting, Cargo will force this to be `no` + # `profile.lto=off` implies `-Cembed-bitcode=no`, but unconditionally embedding + # bitcode is necessary for when users enable LTO. + # Required until Cargo can re-build the standard library based on the value + # of `profile.lto` in the user's profile. "-Cembed-bitcode=yes", # Enable frame pointers "-Zunstable-options", From 733074a6bb95384c533e872ea7afe74be5996388 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Thu, 8 Jan 2026 15:52:50 +0000 Subject: [PATCH 7/9] Don't use debug profile for std when rust.optimize=false --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/builder/cargo.rs | 13 +++++++++---- src/bootstrap/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index a90687c5c0f98..d86159d3cc7e9 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -133,7 +133,7 @@ impl Step for ToolBuild { RustcLto::ThinLocal => None, }; if let Some(lto) = lto { - cargo.env(cargo_profile_var("LTO", &builder.config), lto); + cargo.env(cargo_profile_var("LTO", &builder.config, self.mode), lto); } } diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 041217e1dc8ca..b36fcd990dc62 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -602,7 +602,7 @@ impl Builder<'_> { build_stamp::clear_if_dirty(self, &my_out, &rustdoc); } - let profile_var = |name: &str| cargo_profile_var(name, &self.config); + let profile_var = |name: &str| cargo_profile_var(name, &self.config, mode); // 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. @@ -1437,7 +1437,7 @@ impl Builder<'_> { } else { match (mode, self.config.rust_optimize.is_release()) { // Some std configuration exists in its own profile - (Mode::Std, true) => Some("dist"), + (Mode::Std, _) => Some("dist"), (_, true) => Some("release"), (_, false) => Some("dev"), } @@ -1460,7 +1460,12 @@ impl Builder<'_> { } } -pub fn cargo_profile_var(name: &str, config: &Config) -> String { - let profile = if config.rust_optimize.is_release() { "RELEASE" } else { "DEV" }; +pub fn cargo_profile_var(name: &str, config: &Config, mode: Mode) -> String { + let profile = match (mode, config.rust_optimize.is_release()) { + // Some std configuration exists in its own profile + (Mode::Std, _) => "DIST", + (_, true) => "RELEASE", + (_, false) => "DEV", + }; format!("CARGO_PROFILE_{profile}_{name}") } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7af96bca44bdf..dfa29b5aa3cd3 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -900,7 +900,7 @@ impl Build { /// release/debug) fn cargo_dir(&self, mode: Mode) -> &'static str { match (mode, self.config.rust_optimize.is_release()) { - (Mode::Std, true) => "dist", + (Mode::Std, _) => "dist", (_, true) => "release", (_, false) => "debug", } From f4bd4b1692a4d81991d148092e6f8453129d48b5 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 9 Jan 2026 17:00:35 +0000 Subject: [PATCH 8/9] Avoid passing empty string to rustflags --- src/bootstrap/src/core/builder/cargo.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index b36fcd990dc62..7150b2b0d59f2 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -683,11 +683,13 @@ impl Builder<'_> { rustflags.arg("--cfg=windows_raw_dylib"); } - rustflags.arg(match use_new_symbol_mangling { - Some(true) => "-Csymbol-mangling-version=v0", - Some(false) => "-Csymbol-mangling-version=legacy", - None => "", - }); + if let Some(usm) = use_new_symbol_mangling { + rustflags.arg(if usm { + "-Csymbol-mangling-version=v0" + } else { + "-Csymbol-mangling-version=legacy" + }); + } // Always enable move/copy annotations for profiler visibility (non-stage0 only). // Note that -Zannotate-moves is only effective with debugging info enabled. From 368504e590e4a782668c535ec87c321acd8bfe04 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Fri, 9 Jan 2026 18:03:41 +0000 Subject: [PATCH 9/9] Readd CI debuginfo-level-std directive as bootstrap has to set a level based on the default values of rust.debug[...] keys --- src/ci/run.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ci/run.sh b/src/ci/run.sh index 583ad4461bc3f..b486f0525f40d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -120,6 +120,8 @@ if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then if [ "$DEPLOY_ALT" != "" ] && isLinux; then RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level=2" + else + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1" fi if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then