From b6c9a6a442daa4ef187a23e6f4e4d5ab78702cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 29 Sep 2025 18:25:00 +0200 Subject: [PATCH 01/15] Generalize setting `rust-lld` as the default linker on Linux --- compiler/rustc_target/src/spec/base/linux_gnu.rs | 13 +++++++++++-- .../src/spec/targets/x86_64_unknown_linux_gnu.rs | 7 ------- src/bootstrap/src/core/build_steps/compile.rs | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/linux_gnu.rs b/compiler/rustc_target/src/spec/base/linux_gnu.rs index e9135b43ebc1f..2fcd8c61a9c62 100644 --- a/compiler/rustc_target/src/spec/base/linux_gnu.rs +++ b/compiler/rustc_target/src/spec/base/linux_gnu.rs @@ -1,5 +1,14 @@ -use crate::spec::{TargetOptions, base}; +use crate::spec::{Cc, LinkerFlavor, Lld, TargetOptions, base}; pub(crate) fn opts() -> TargetOptions { - TargetOptions { env: "gnu".into(), ..base::linux::opts() } + let mut base = TargetOptions { env: "gnu".into(), ..base::linux::opts() }; + + // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using + // linker flavor, and self-contained linker component. + if option_env!("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC").is_some() { + base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes); + base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker(); + } + + base } diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs index 0c8353fad182f..59bb7f5962101 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs @@ -20,13 +20,6 @@ pub(crate) fn target() -> Target { | SanitizerSet::THREAD; base.supports_xray = true; - // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using - // linker flavor, and self-contained linker component. - if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() { - base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes); - base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker(); - } - Target { llvm_target: "x86_64-unknown-linux-gnu".into(), metadata: TargetMetadata { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index d29d1041486bd..6c34b62491962 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1357,7 +1357,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS // Enable rustc's env var for `rust-lld` when requested. if builder.config.lld_enabled { - cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1"); + cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1"); } if builder.config.rust_verify_llvm_ir { From 8dd97f887ceb8376ddf24b8b34d36019d249b74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 29 Sep 2025 17:39:30 +0200 Subject: [PATCH 02/15] Destructure `TomlConfig` and add missing `default_linker` config --- src/bootstrap/src/core/config/config.rs | 78 +++++++++++++++++-------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1fcc1174e856c..84457e7c3345b 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -44,7 +44,7 @@ use crate::core::config::toml::rust::{ BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc, default_lld_opt_in_targets, parse_codegen_backends, }; -use crate::core::config::toml::target::Target; +use crate::core::config::toml::target::{Target, TomlTarget}; use crate::core::config::{ CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, @@ -831,9 +831,36 @@ impl Config { if let Some(t) = toml.target { for (triple, cfg) in t { + let TomlTarget { + cc: target_cc, + cxx: target_cxx, + ar: target_ar, + ranlib: target_ranlib, + default_linker: target_default_linker, + linker: target_linker, + split_debuginfo: target_split_debuginfo, + llvm_config: target_llvm_config, + llvm_has_rust_patches: target_llvm_has_rust_patches, + llvm_filecheck: target_llvm_filecheck, + llvm_libunwind: target_llvm_libunwind, + sanitizers: target_sanitizers, + profiler: target_profiler, + rpath: target_rpath, + crt_static: target_crt_static, + musl_root: target_musl_root, + musl_libdir: target_musl_libdir, + wasi_root: target_wasi_root, + qemu_rootfs: target_qemu_rootfs, + no_std: target_no_std, + codegen_backends: target_codegen_backends, + runner: target_runner, + optimized_compiler_builtins: target_optimized_compiler_builtins, + jemalloc: target_jemalloc, + } = cfg; + let mut target = Target::from_triple(&triple); - if let Some(ref s) = cfg.llvm_config { + if let Some(ref s) = target_llvm_config { if download_rustc_commit.is_some() && triple == *host_target.triple { panic!( "setting llvm_config for the host is incompatible with download-rustc" @@ -841,46 +868,47 @@ impl Config { } target.llvm_config = Some(src.join(s)); } - if let Some(patches) = cfg.llvm_has_rust_patches { + if let Some(patches) = target_llvm_has_rust_patches { assert!( - build_submodules == Some(false) || cfg.llvm_config.is_some(), + build_submodules == Some(false) || target_llvm_config.is_some(), "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" ); target.llvm_has_rust_patches = Some(patches); } - if let Some(ref s) = cfg.llvm_filecheck { + if let Some(ref s) = target_llvm_filecheck { target.llvm_filecheck = Some(src.join(s)); } - target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { + target.llvm_libunwind = target_llvm_libunwind.as_ref().map(|v| { v.parse().unwrap_or_else(|_| { panic!("failed to parse target.{triple}.llvm-libunwind") }) }); - if let Some(s) = cfg.no_std { + if let Some(s) = target_no_std { target.no_std = s; } - target.cc = cfg.cc.map(PathBuf::from); - target.cxx = cfg.cxx.map(PathBuf::from); - target.ar = cfg.ar.map(PathBuf::from); - target.ranlib = cfg.ranlib.map(PathBuf::from); - target.linker = cfg.linker.map(PathBuf::from); - target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); - target.wasi_root = cfg.wasi_root.map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); - target.runner = cfg.runner; - target.sanitizers = cfg.sanitizers; - target.profiler = cfg.profiler; - target.rpath = cfg.rpath; - target.optimized_compiler_builtins = cfg.optimized_compiler_builtins; - target.jemalloc = cfg.jemalloc; - if let Some(backends) = cfg.codegen_backends { + target.cc = target_cc.map(PathBuf::from); + target.cxx = target_cxx.map(PathBuf::from); + target.ar = target_ar.map(PathBuf::from); + target.ranlib = target_ranlib.map(PathBuf::from); + target.linker = target_linker.map(PathBuf::from); + target.crt_static = target_crt_static; + target.default_linker = target_default_linker; + target.musl_root = target_musl_root.map(PathBuf::from); + target.musl_libdir = target_musl_libdir.map(PathBuf::from); + target.wasi_root = target_wasi_root.map(PathBuf::from); + target.qemu_rootfs = target_qemu_rootfs.map(PathBuf::from); + target.runner = target_runner; + target.sanitizers = target_sanitizers; + target.profiler = target_profiler; + target.rpath = target_rpath; + target.optimized_compiler_builtins = target_optimized_compiler_builtins; + target.jemalloc = target_jemalloc; + if let Some(backends) = target_codegen_backends { target.codegen_backends = Some(parse_codegen_backends(backends, &format!("target.{triple}"))) } - target.split_debuginfo = cfg.split_debuginfo.as_ref().map(|v| { + target.split_debuginfo = target_split_debuginfo.as_ref().map(|v| { v.parse().unwrap_or_else(|_| { panic!("invalid value for target.{triple}.split-debuginfo") }) From 902cec2bc6997748e2ca47c11dba8acc673806d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 6 Oct 2025 10:30:31 +0200 Subject: [PATCH 03/15] Allow manually opting in and out of Linux linker overrides --- bootstrap.example.toml | 22 +++-- src/bootstrap/src/core/build_steps/compile.rs | 12 ++- src/bootstrap/src/core/builder/tests.rs | 33 ++++++- src/bootstrap/src/core/config/config.rs | 94 ++++++++++++++----- src/bootstrap/src/core/config/toml/rust.rs | 25 ----- src/bootstrap/src/core/config/toml/target.rs | 62 ++++++++++++ 6 files changed, 185 insertions(+), 63 deletions(-) diff --git a/bootstrap.example.toml b/bootstrap.example.toml index f623a3db0029d..6f37e51a47de2 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -758,12 +758,8 @@ # Currently, the only standard options supported here are `"llvm"`, `"cranelift"` and `"gcc"`. #rust.codegen-backends = ["llvm"] -# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and -# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be -# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from -# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will -# make this default to false. -#rust.lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true +# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, +#rust.lld = false, except for targets that opt into LLD (see `target.default-linker-linux-override`) # Indicates if we should override the linker used to link Rust crates during bootstrap to be LLD. # If set to `true` or `"external"`, a global `lld` binary that has to be in $PATH @@ -1067,3 +1063,17 @@ # Link the compiler and LLVM against `jemalloc` instead of the default libc allocator. # This overrides the global `rust.jemalloc` option. See that option for more info. #jemalloc = rust.jemalloc (bool) + +# The linker configuration that will *override* the default linker used for Linux +# targets in the built compiler. +# +# The following values are supported: +# - `off` => do not apply any override and use the default linker. This can be used to opt out of +# linker overrides set by bootstrap for specific targets (see below). +# - `self-contained-lld-cc` => override the default linker to be self-contained LLD (`rust-lld`) +# that is invoked through `cc`. +# +# Currently, the following targets automatically opt into the self-contained LLD linker, unless you +# pass `off`: +# - x86_64-unknown-linux-gnu +#default-linker-linux-override = "off" (for most targets) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6c34b62491962..dd90ac7cdda31 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -26,6 +26,7 @@ use crate::core::builder; use crate::core::builder::{ Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, }; +use crate::core::config::toml::target::DefaultLinuxLinkerOverride; use crate::core::config::{ CompilerBuiltins, DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection, }; @@ -1355,9 +1356,14 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS cargo.env("CFG_DEFAULT_LINKER", s); } - // Enable rustc's env var for `rust-lld` when requested. - if builder.config.lld_enabled { - cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1"); + // Enable rustc's env var to use a linker override on Linux when requested. + if let Some(linker) = target_config.map(|c| c.default_linker_linux_override) { + match linker { + DefaultLinuxLinkerOverride::Off => {} + DefaultLinuxLinkerOverride::SelfContainedLldCc => { + cargo.env("CFG_DEFAULT_LINKER_SELF_CONTAINED_LLD_CC", "1"); + } + } } if builder.config.rust_verify_llvm_ir { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index d0429387f824e..e0eb38d04aad0 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -514,7 +514,9 @@ mod snapshot { }; use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata}; use crate::core::config::TargetSelection; - use crate::core::config::toml::rust::with_lld_opt_in_targets; + use crate::core::config::toml::target::{ + DefaultLinuxLinkerOverride, with_default_linux_linker_overrides, + }; use crate::utils::cache::Cache; use crate::utils::helpers::get_host_target; use crate::utils::tests::{ConfigBuilder, TestCtx}; @@ -782,9 +784,11 @@ mod snapshot { #[test] fn build_compiler_lld_opt_in() { - with_lld_opt_in_targets(vec![host_target()], || { - let ctx = TestCtx::new(); - insta::assert_snapshot!( + with_default_linux_linker_overrides( + [(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(), + || { + let ctx = TestCtx::new(); + insta::assert_snapshot!( ctx.config("build") .path("compiler") .render_steps(), @r" @@ -792,7 +796,26 @@ mod snapshot { [build] rustc 0 -> rustc 1 [build] rustc 0 -> LldWrapper 1 "); - }); + }, + ); + } + + #[test] + fn build_compiler_lld_opt_in_lld_disabled() { + with_default_linux_linker_overrides( + [(host_target(), DefaultLinuxLinkerOverride::SelfContainedLldCc)].into(), + || { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("build") + .path("compiler") + .args(&["--set", "rust.lld=false"]) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + "); + }, + ); } #[test] diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 84457e7c3345b..0a5c342835028 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -42,9 +42,11 @@ use crate::core::config::toml::install::Install; use crate::core::config::toml::llvm::Llvm; use crate::core::config::toml::rust::{ BootstrapOverrideLld, Rust, RustOptimize, check_incompatible_options_for_ci_rustc, - default_lld_opt_in_targets, parse_codegen_backends, + parse_codegen_backends, +}; +use crate::core::config::toml::target::{ + DefaultLinuxLinkerOverride, Target, TomlTarget, default_linux_linker_overrides, }; -use crate::core::config::toml::target::{Target, TomlTarget}; use crate::core::config::{ CompilerBuiltins, DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, StringOrBool, threads_from_config, @@ -829,6 +831,11 @@ impl Config { .to_owned(); } + let mut lld_enabled = rust_lld_enabled.unwrap_or(false); + + // Linux targets for which the user explicitly overrode the used linker + let mut targets_with_user_linker_override = HashSet::new(); + if let Some(t) = toml.target { for (triple, cfg) in t { let TomlTarget { @@ -837,6 +844,7 @@ impl Config { ar: target_ar, ranlib: target_ranlib, default_linker: target_default_linker, + default_linker_linux: target_default_linker_linux_override, linker: target_linker, split_debuginfo: target_split_debuginfo, llvm_config: target_llvm_config, @@ -860,6 +868,33 @@ impl Config { let mut target = Target::from_triple(&triple); + if target_default_linker_linux_override.is_some() { + targets_with_user_linker_override.insert(triple.clone()); + } + + let default_linker_linux_override = match target_default_linker_linux_override { + Some(DefaultLinuxLinkerOverride::SelfContainedLldCc) => { + if rust_default_linker.is_some() { + panic!( + "cannot set both `default-linker` and `default-linker-linux` for target `{triple}`" + ); + } + if !triple.contains("linux-gnu") { + panic!( + "`default-linker-linux` can only be set for Linux GNU targets, not for `{triple}`" + ); + } + if !lld_enabled { + panic!( + "Trying to override the default Linux linker for `{triple}` to be self-contained LLD, but LLD is not being built. Enable it with rust.lld = true." + ); + } + DefaultLinuxLinkerOverride::SelfContainedLldCc + } + Some(DefaultLinuxLinkerOverride::Off) => DefaultLinuxLinkerOverride::Off, + None => DefaultLinuxLinkerOverride::default(), + }; + if let Some(ref s) = target_llvm_config { if download_rustc_commit.is_some() && triple == *host_target.triple { panic!( @@ -893,6 +928,7 @@ impl Config { target.linker = target_linker.map(PathBuf::from); target.crt_static = target_crt_static; target.default_linker = target_default_linker; + target.default_linker_linux_override = default_linker_linux_override; target.musl_root = target_musl_root.map(PathBuf::from); target.musl_libdir = target_musl_libdir.map(PathBuf::from); target.wasi_root = target_wasi_root.map(PathBuf::from); @@ -918,6 +954,38 @@ impl Config { } } + for (target, linker_override) in default_linux_linker_overrides() { + // If the user overrode the default Linux linker, do not apply bootstrap defaults + if targets_with_user_linker_override.contains(&target) { + continue; + } + let default_linux_linker_override = match linker_override { + DefaultLinuxLinkerOverride::Off => continue, + DefaultLinuxLinkerOverride::SelfContainedLldCc => { + // If we automatically default to the self-contained LLD linker, + // we also need to handle the rust.lld option. + match rust_lld_enabled { + // If LLD was not enabled explicitly, we enable it + None => { + lld_enabled = true; + Some(DefaultLinuxLinkerOverride::SelfContainedLldCc) + } + // If it was enabled already, we don't need to do anything + Some(true) => Some(DefaultLinuxLinkerOverride::SelfContainedLldCc), + // If it was explicitly disabled, we do not apply the + // linker override + Some(false) => None, + } + } + }; + if let Some(linker_override) = default_linux_linker_override { + target_config + .entry(TargetSelection::from_user(&target)) + .or_default() + .default_linker_linux_override = linker_override; + } + } + let llvm_from_ci = parse_download_ci_llvm( &dwn_ctx, &rust_info, @@ -926,28 +994,6 @@ impl Config { 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 - // to true by default: - // - on the `x86_64-unknown-linux-gnu` target - // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that - // we're also able to build the corresponding lld - // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt - // lld - // - otherwise, we'd be using an external llvm, and lld would not necessarily available and - // thus, disabled - // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. - // when the config sets `rust.lld = false` - let lld_enabled = if default_lld_opt_in_targets().contains(&host_target.triple.to_string()) - && hosts == [host_target] - { - let no_llvm_config = - target_config.get(&host_target).is_none_or(|config| config.llvm_config.is_none()); - rust_lld_enabled.unwrap_or(llvm_from_ci || no_llvm_config) - } else { - rust_lld_enabled.unwrap_or(false) - }; - if llvm_from_ci { let warn = |option: &str| { println!( diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index ca9e0d0bc98e7..5a2c6e1698698 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -438,28 +438,3 @@ pub(crate) fn parse_codegen_backends( } found_backends } - -#[cfg(not(test))] -pub fn default_lld_opt_in_targets() -> Vec { - vec!["x86_64-unknown-linux-gnu".to_string()] -} - -#[cfg(test)] -thread_local! { - static TEST_LLD_OPT_IN_TARGETS: std::cell::RefCell>> = std::cell::RefCell::new(None); -} - -#[cfg(test)] -pub fn default_lld_opt_in_targets() -> Vec { - TEST_LLD_OPT_IN_TARGETS.with(|cell| cell.borrow().clone()).unwrap_or_default() -} - -#[cfg(test)] -pub fn with_lld_opt_in_targets(targets: Vec, f: impl FnOnce() -> R) -> R { - TEST_LLD_OPT_IN_TARGETS.with(|cell| { - let prev = cell.replace(Some(targets)); - let result = f(); - cell.replace(prev); - result - }) -} diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 020602e6a1997..7b8d4f9601b53 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -9,6 +9,9 @@ //! * [`Target`]: This struct represents the processed and validated configuration for a //! build target, which is is stored in the main `Config` structure. +use std::collections::HashMap; + +use serde::de::Error; use serde::{Deserialize, Deserializer}; use crate::core::config::{ @@ -24,6 +27,7 @@ define_config! { ar: Option = "ar", ranlib: Option = "ranlib", default_linker: Option = "default-linker", + default_linker_linux: Option = "default-linker-linux-override", linker: Option = "linker", split_debuginfo: Option = "split-debuginfo", llvm_config: Option = "llvm-config", @@ -60,6 +64,7 @@ pub struct Target { pub ar: Option, pub ranlib: Option, pub default_linker: Option, + pub default_linker_linux_override: DefaultLinuxLinkerOverride, pub linker: Option, pub split_debuginfo: Option, pub sanitizers: Option, @@ -89,3 +94,60 @@ impl Target { target } } + +/// Overrides the default linker used on a Linux linker. +/// On Linux, the linker is usually invoked through `cc`, therefore this exists as a separate +/// configuration from simply setting `default-linker`, which corresponds to `-Clinker`. +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] +pub enum DefaultLinuxLinkerOverride { + /// Do not apply any override and use the default linker for the given target. + #[default] + Off, + /// Use the self-contained `rust-lld` linker, invoked through `cc`. + /// Corresponds to `-Clinker-features=+lld -Clink-self-contained=+linker`. + SelfContainedLldCc, +} + +impl<'de> Deserialize<'de> for DefaultLinuxLinkerOverride { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let name = String::deserialize(deserializer)?; + match name.as_str() { + "off" => Ok(Self::Off), + "self-contained-lld-cc" => Ok(Self::SelfContainedLldCc), + other => Err(D::Error::unknown_variant(other, &["off", "self-contained-lld-cc"])), + } + } +} + +/// Set of linker overrides for selected Linux targets. +#[cfg(not(test))] +pub fn default_linux_linker_overrides() -> HashMap { + [("x86_64-unknown-linux-gnu".to_string(), DefaultLinuxLinkerOverride::SelfContainedLldCc)] + .into() +} + +#[cfg(test)] +thread_local! { + static TEST_LINUX_LINKER_OVERRIDES: std::cell::RefCell>> = std::cell::RefCell::new(None); +} + +#[cfg(test)] +pub fn default_linux_linker_overrides() -> HashMap { + TEST_LINUX_LINKER_OVERRIDES.with(|cell| cell.borrow().clone()).unwrap_or_default() +} + +#[cfg(test)] +pub fn with_default_linux_linker_overrides( + targets: HashMap, + f: impl FnOnce() -> R, +) -> R { + TEST_LINUX_LINKER_OVERRIDES.with(|cell| { + let prev = cell.replace(Some(targets)); + let result = f(); + cell.replace(prev); + result + }) +} From e7c9e12ce441766ad62f73d1b354edaa0a4ebc30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 29 Sep 2025 18:04:32 +0200 Subject: [PATCH 04/15] Update change tracker --- src/bootstrap/src/utils/change_tracker.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 853fc4e6623e9..ea5fc77c8a4a8 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -566,4 +566,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "`compiletest` is now always built with the stage 0 compiler, so `build.compiletest-use-stage0-libtest` has no effect.", }, + ChangeInfo { + change_id: 147157, + severity: ChangeSeverity::Warning, + summary: "`rust.lld = true` no longer automatically causes the `x86_64-unknown-linux-gnu` target to default into using the self-contained LLD linker. This target now uses the LLD linker by default. To opt out, set `target.x86_64-unknown-linux-gnu.default-linker-linux-override = 'off'`.", + }, ]; From b07d88fc725a2aac8a402c7127a17e0d2119e822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 6 Oct 2025 10:43:16 +0200 Subject: [PATCH 05/15] Handle external LLVM config --- src/bootstrap/src/core/config/config.rs | 81 +++++++++++++------------ 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 0a5c342835028..02dd3f0c05c50 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -954,38 +954,6 @@ impl Config { } } - for (target, linker_override) in default_linux_linker_overrides() { - // If the user overrode the default Linux linker, do not apply bootstrap defaults - if targets_with_user_linker_override.contains(&target) { - continue; - } - let default_linux_linker_override = match linker_override { - DefaultLinuxLinkerOverride::Off => continue, - DefaultLinuxLinkerOverride::SelfContainedLldCc => { - // If we automatically default to the self-contained LLD linker, - // we also need to handle the rust.lld option. - match rust_lld_enabled { - // If LLD was not enabled explicitly, we enable it - None => { - lld_enabled = true; - Some(DefaultLinuxLinkerOverride::SelfContainedLldCc) - } - // If it was enabled already, we don't need to do anything - Some(true) => Some(DefaultLinuxLinkerOverride::SelfContainedLldCc), - // If it was explicitly disabled, we do not apply the - // linker override - Some(false) => None, - } - } - }; - if let Some(linker_override) = default_linux_linker_override { - target_config - .entry(TargetSelection::from_user(&target)) - .or_default() - .default_linker_linux_override = linker_override; - } - } - let llvm_from_ci = parse_download_ci_llvm( &dwn_ctx, &rust_info, @@ -993,6 +961,8 @@ impl Config { llvm_download_ci_llvm, llvm_assertions, ); + let is_host_system_llvm = + is_system_llvm(&target_config, llvm_from_ci, host_target, host_target); if llvm_from_ci { let warn = |option: &str| { @@ -1040,6 +1010,41 @@ impl Config { build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target))); } + for (target, linker_override) in default_linux_linker_overrides() { + // If the user overrode the default Linux linker, do not apply bootstrap defaults + if targets_with_user_linker_override.contains(&target) { + continue; + } + + let default_linux_linker_override = match linker_override { + DefaultLinuxLinkerOverride::Off => continue, + DefaultLinuxLinkerOverride::SelfContainedLldCc => { + // If we automatically default to the self-contained LLD linker, + // we also need to handle the rust.lld option. + match rust_lld_enabled { + // If LLD was not enabled explicitly, we enable it, unless LLVM config has + // been set + None if !is_host_system_llvm => { + lld_enabled = true; + Some(DefaultLinuxLinkerOverride::SelfContainedLldCc) + } + None => None, + // If it was enabled already, we don't need to do anything + Some(true) => Some(DefaultLinuxLinkerOverride::SelfContainedLldCc), + // If it was explicitly disabled, we do not apply the + // linker override + Some(false) => None, + } + } + }; + if let Some(linker_override) = default_linux_linker_override { + target_config + .entry(TargetSelection::from_user(&target)) + .or_default() + .default_linker_linux_override = linker_override; + } + } + let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out)); if matches!(bootstrap_override_lld, BootstrapOverrideLld::SelfContained) @@ -1051,7 +1056,7 @@ impl Config { ); } - if lld_enabled && is_system_llvm(&dwn_ctx, &target_config, llvm_from_ci, host_target) { + if lld_enabled && is_host_system_llvm { panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } @@ -1845,8 +1850,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, &self.target_config, self.llvm_from_ci, target) + is_system_llvm(&self.target_config, self.llvm_from_ci, self.host_target, target) } /// Returns `true` if this is our custom, patched, version of LLVM. @@ -2449,16 +2453,15 @@ pub fn submodules_(submodules: &Option, rust_info: &channel::GitInfo) -> b /// In particular, we expect llvm sources to be available when this is false. /// /// 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>, +pub fn is_system_llvm( target_config: &HashMap, llvm_from_ci: bool, + host_target: TargetSelection, target: TargetSelection, ) -> bool { - let dwn_ctx = dwn_ctx.as_ref(); match target_config.get(&target) { Some(Target { llvm_config: Some(_), .. }) => { - let ci_llvm = llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target); + let ci_llvm = llvm_from_ci && is_host_target(&host_target, &target); !ci_llvm } // We're building from the in-tree src/llvm-project sources. From 345241536fbd2302c032851c0422f18ed847a0df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Oct 2025 11:15:31 +0200 Subject: [PATCH 06/15] repr_transparent_external_private_fields: normalize types during traversal --- .../rustc_hir_analysis/src/check/check.rs | 15 ++++--- .../repr/repr-transparent-non-exhaustive.rs | 12 +++++ .../repr-transparent-non-exhaustive.stderr | 44 ++++++++++++------- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 9c2d52c3e8030..4c910d25c30a8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1510,11 +1510,11 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) return; } + let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did()); // For each field, figure out if it's known to have "trivial" layout (i.e., is a 1-ZST), with // "known" respecting #[non_exhaustive] attributes. let field_infos = adt.all_fields().map(|field| { let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did)); - let typing_env = ty::TypingEnv::non_body_analysis(tcx, field.did); let layout = tcx.layout_of(typing_env.as_query_input(ty)); // We are currently checking the type this field came from, so it must be local let span = tcx.hir_span_if_local(field.did).unwrap(); @@ -1526,11 +1526,16 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) fn check_non_exhaustive<'tcx>( tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, t: Ty<'tcx>, ) -> ControlFlow<(&'static str, DefId, GenericArgsRef<'tcx>, bool)> { + // We can encounter projections during traversal, so ensure the type is normalized. + let t = tcx.try_normalize_erasing_regions(typing_env, t).unwrap_or(t); match t.kind() { - ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)), - ty::Array(ty, _) => check_non_exhaustive(tcx, *ty), + ty::Tuple(list) => { + list.iter().try_for_each(|t| check_non_exhaustive(tcx, typing_env, t)) + } + ty::Array(ty, _) => check_non_exhaustive(tcx, typing_env, *ty), ty::Adt(def, args) => { if !def.did().is_local() && !find_attr!( @@ -1555,13 +1560,13 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) } def.all_fields() .map(|field| field.ty(tcx, args)) - .try_for_each(|t| check_non_exhaustive(tcx, t)) + .try_for_each(|t| check_non_exhaustive(tcx, typing_env, t)) } _ => ControlFlow::Continue(()), } } - (span, trivial, check_non_exhaustive(tcx, ty).break_value()) + (span, trivial, check_non_exhaustive(tcx, typing_env, ty).break_value()) }); let non_trivial_fields = field_infos diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.rs b/tests/ui/repr/repr-transparent-non-exhaustive.rs index 9894b89e8e418..38bab0163b4c5 100644 --- a/tests/ui/repr/repr-transparent-non-exhaustive.rs +++ b/tests/ui/repr/repr-transparent-non-exhaustive.rs @@ -24,6 +24,13 @@ pub struct InternalIndirection { pub type Sized = i32; +pub trait Trait { + type Assoc; +} +impl Trait for i32 { + type Assoc = NonExhaustive; +} + #[repr(transparent)] pub struct T1(Sized, InternalPrivate); #[repr(transparent)] @@ -43,6 +50,11 @@ pub struct T6(Sized, NonExhaustive); //~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types //~| WARN this was previously accepted by the compiler +#[repr(transparent)] +pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` +//~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types +//~| WARN this was previously accepted by the compiler + #[repr(transparent)] pub struct T7(Sized, NonExhaustiveEnum); //~^ ERROR zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types diff --git a/tests/ui/repr/repr-transparent-non-exhaustive.stderr b/tests/ui/repr/repr-transparent-non-exhaustive.stderr index 808b9bc986d91..27ba6e82a539a 100644 --- a/tests/ui/repr/repr-transparent-non-exhaustive.stderr +++ b/tests/ui/repr/repr-transparent-non-exhaustive.stderr @@ -1,5 +1,5 @@ error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:37:22 + --> $DIR/repr-transparent-non-exhaustive.rs:44:22 | LL | pub struct T5(Sized, Private); | ^^^^^^^ @@ -14,7 +14,7 @@ LL | #![deny(repr_transparent_external_private_fields)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:42:22 + --> $DIR/repr-transparent-non-exhaustive.rs:49:22 | LL | pub struct T6(Sized, NonExhaustive); | ^^^^^^^^^^^^^ @@ -24,7 +24,17 @@ LL | pub struct T6(Sized, NonExhaustive); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:47:22 + --> $DIR/repr-transparent-non-exhaustive.rs:54:23 + | +LL | pub struct T6a(Sized, ::Assoc); // normalizes to `NonExhaustive` + | ^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #78586 + = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. + +error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types + --> $DIR/repr-transparent-non-exhaustive.rs:59:22 | LL | pub struct T7(Sized, NonExhaustiveEnum); | ^^^^^^^^^^^^^^^^^ @@ -34,7 +44,7 @@ LL | pub struct T7(Sized, NonExhaustiveEnum); = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:52:22 + --> $DIR/repr-transparent-non-exhaustive.rs:64:22 | LL | pub struct T8(Sized, NonExhaustiveVariant); | ^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +54,7 @@ LL | pub struct T8(Sized, NonExhaustiveVariant); = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:57:22 + --> $DIR/repr-transparent-non-exhaustive.rs:69:22 | LL | pub struct T9(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -54,7 +64,7 @@ LL | pub struct T9(Sized, InternalIndirection); = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:62:23 + --> $DIR/repr-transparent-non-exhaustive.rs:74:23 | LL | pub struct T10(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +74,7 @@ LL | pub struct T10(Sized, InternalIndirection); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:67:23 + --> $DIR/repr-transparent-non-exhaustive.rs:79:23 | LL | pub struct T11(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +84,7 @@ LL | pub struct T11(Sized, InternalIndirection); = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:72:23 + --> $DIR/repr-transparent-non-exhaustive.rs:84:23 | LL | pub struct T12(Sized, InternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +94,7 @@ LL | pub struct T12(Sized, InternalIndirection); = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:77:23 + --> $DIR/repr-transparent-non-exhaustive.rs:89:23 | LL | pub struct T13(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +104,7 @@ LL | pub struct T13(Sized, ExternalIndirection); = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:82:23 + --> $DIR/repr-transparent-non-exhaustive.rs:94:23 | LL | pub struct T14(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +114,7 @@ LL | pub struct T14(Sized, ExternalIndirection); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:87:23 + --> $DIR/repr-transparent-non-exhaustive.rs:99:23 | LL | pub struct T15(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +124,7 @@ LL | pub struct T15(Sized, ExternalIndirection); = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:92:23 + --> $DIR/repr-transparent-non-exhaustive.rs:104:23 | LL | pub struct T16(Sized, ExternalIndirection); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +134,7 @@ LL | pub struct T16(Sized, ExternalIndirection); = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:97:16 + --> $DIR/repr-transparent-non-exhaustive.rs:109:16 | LL | pub struct T17(NonExhaustive, Sized); | ^^^^^^^^^^^^^ @@ -134,7 +144,7 @@ LL | pub struct T17(NonExhaustive, Sized); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:102:31 + --> $DIR/repr-transparent-non-exhaustive.rs:114:31 | LL | pub struct T18(NonExhaustive, NonExhaustive); | ^^^^^^^^^^^^^ @@ -144,7 +154,7 @@ LL | pub struct T18(NonExhaustive, NonExhaustive); = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:107:31 + --> $DIR/repr-transparent-non-exhaustive.rs:119:31 | LL | pub struct T19(NonExhaustive, Private); | ^^^^^^^ @@ -154,7 +164,7 @@ LL | pub struct T19(NonExhaustive, Private); = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future. error: zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types - --> $DIR/repr-transparent-non-exhaustive.rs:112:32 + --> $DIR/repr-transparent-non-exhaustive.rs:124:32 | LL | pub struct T19Flipped(Private, NonExhaustive); | ^^^^^^^^^^^^^ @@ -163,5 +173,5 @@ LL | pub struct T19Flipped(Private, NonExhaustive); = note: for more information, see issue #78586 = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future. -error: aborting due to 16 previous errors +error: aborting due to 17 previous errors From da86710c307d5a411534ba7b1bf22a87f8b2afa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Thu, 9 Oct 2025 17:19:23 +0200 Subject: [PATCH 07/15] Rename default linker linux field --- src/bootstrap/src/core/config/config.rs | 2 +- src/bootstrap/src/core/config/toml/target.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 02dd3f0c05c50..85388d3b4639e 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -844,7 +844,7 @@ impl Config { ar: target_ar, ranlib: target_ranlib, default_linker: target_default_linker, - default_linker_linux: target_default_linker_linux_override, + default_linker_linux_override: target_default_linker_linux_override, linker: target_linker, split_debuginfo: target_split_debuginfo, llvm_config: target_llvm_config, diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 7b8d4f9601b53..4c7afa50b9658 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -27,7 +27,7 @@ define_config! { ar: Option = "ar", ranlib: Option = "ranlib", default_linker: Option = "default-linker", - default_linker_linux: Option = "default-linker-linux-override", + default_linker_linux_override: Option = "default-linker-linux-override", linker: Option = "linker", split_debuginfo: Option = "split-debuginfo", llvm_config: Option = "llvm-config", @@ -95,7 +95,7 @@ impl Target { } } -/// Overrides the default linker used on a Linux linker. +/// Overrides the default linker used on a Linux target. /// On Linux, the linker is usually invoked through `cc`, therefore this exists as a separate /// configuration from simply setting `default-linker`, which corresponds to `-Clinker`. #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] From 10393a805292ebdc28c2787e0889f369b11b12f6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 12 Oct 2025 21:33:38 +1100 Subject: [PATCH 08/15] Add LLDB commands to `tests/debuginfo/basic-types-globals.rs` --- tests/debuginfo/basic-types-globals.rs | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/debuginfo/basic-types-globals.rs b/tests/debuginfo/basic-types-globals.rs index 9d28820ce685c..41b231c7f13ee 100644 --- a/tests/debuginfo/basic-types-globals.rs +++ b/tests/debuginfo/basic-types-globals.rs @@ -6,6 +6,38 @@ //@ [lto] compile-flags:-C lto //@ [lto] no-prefer-dynamic +// lldb-command:run +// lldb-command:v B +// lldb-check: ::B::[...] = false +// lldb-command:v I +// lldb-check: ::I::[...] = -1 +// lldb-command:v --format=d C +// lldb-check: ::C::[...] = 97 +// lldb-command:v --format=d I8 +// lldb-check: ::I8::[...] = 68 +// lldb-command:v I16 +// lldb-check: ::I16::[...] = -16 +// lldb-command:v I32 +// lldb-check: ::I32::[...] = -32 +// lldb-command:v I64 +// lldb-check: ::I64::[...] = -64 +// lldb-command:v U +// lldb-check: ::U::[...] = 1 +// lldb-command:v --format=d U8 +// lldb-check: ::U8::[...] = 100 +// lldb-command:v U16 +// lldb-check: ::U16::[...] = 16 +// lldb-command:v U32 +// lldb-check: ::U32::[...] = 32 +// lldb-command:v U64 +// lldb-check: ::U64::[...] = 64 +// lldb-command:v F16 +// lldb-check: ::F16::[...] = 1.5 +// lldb-command:v F32 +// lldb-check: ::F32::[...] = 2.5 +// lldb-command:v F64 +// lldb-check: ::F64::[...] = 3.5 + // gdb-command:run // gdb-command:print B // gdb-check:$1 = false From 2be88e39eae5e34097323606677cde594a186eaf Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 12 Oct 2025 20:14:54 +1100 Subject: [PATCH 09/15] Add doc links between `{integer}::from_str_radix` and `from_str` --- library/core/src/num/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c75ee11d15efe..35141dfeb3a6d 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1422,6 +1422,10 @@ macro_rules! from_str_int_impl { /// whitespace) represent an error. Underscores (which are accepted in Rust literals) /// also represent an error. /// + /// # See also + /// For parsing numbers in other bases, such as binary or hexadecimal, + /// see [`from_str_radix`][Self::from_str_radix]. + /// /// # Examples /// /// ``` @@ -1467,6 +1471,14 @@ macro_rules! from_str_int_impl { /// /// This function panics if `radix` is not in the range from 2 to 36. /// + /// # See also + /// If the string to be parsed is in base 10 (decimal), + /// [`from_str`] or [`str::parse`] can also be used. + /// + // FIXME(#122566): These HTML links work around a rustdoc-json test failure. + /// [`from_str`]: #method.from_str + /// [`str::parse`]: primitive.str.html#method.parse + /// /// # Examples /// /// ``` From b6ea8242fd250b2dd6e94433d10a13f9f2d2b1f6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 4 Oct 2025 23:21:10 +1000 Subject: [PATCH 10/15] Hoist some stranded `use` declarations --- compiler/rustc_codegen_llvm/src/debuginfo/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index f61c25bccfad3..e43ff986db6a0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -28,6 +28,8 @@ use rustc_target::spec::DebuginfoKind; use smallvec::SmallVec; use tracing::debug; +use self::create_scope_map::compute_mir_scopes; +pub(crate) use self::metadata::build_global_var_di_node; use self::metadata::{ UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node, }; @@ -48,9 +50,6 @@ pub(crate) mod metadata; mod namespace; mod utils; -use self::create_scope_map::compute_mir_scopes; -pub(crate) use self::metadata::build_global_var_di_node; - /// A context object for maintaining all state needed by the debuginfo module. pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> { llmod: &'ll llvm::Module, From 45e9ebee31dd2b9890ba678eacffe86eea33363d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 4 Oct 2025 22:43:48 +1000 Subject: [PATCH 11/15] Extract `DIBuilderExt::create_expression` --- .../src/debuginfo/di_builder.rs | 21 +++++++++++++++++++ .../rustc_codegen_llvm/src/debuginfo/mod.rs | 6 +++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs new file mode 100644 index 0000000000000..33657a049ad4b --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs @@ -0,0 +1,21 @@ +use crate::llvm; +use crate::llvm::debuginfo::DIBuilder; + +/// Extension trait for defining safe wrappers and helper methods on +/// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate. +pub(crate) trait DIBuilderExt<'ll> { + fn as_di_builder(&self) -> &DIBuilder<'ll>; + + fn create_expression(&self, addr_ops: &[u64]) -> &'ll llvm::Metadata { + let this = self.as_di_builder(); + unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) } + } +} + +impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> { + fn as_di_builder(&self) -> &DIBuilder<'ll> { + self + } + + // All other methods have default bodies that rely on `as_di_builder`. +} diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index e43ff986db6a0..b95ad03b70e03 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -29,6 +29,7 @@ use smallvec::SmallVec; use tracing::debug; use self::create_scope_map::compute_mir_scopes; +pub(crate) use self::di_builder::DIBuilderExt; pub(crate) use self::metadata::build_global_var_di_node; use self::metadata::{ UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER, file_metadata, spanned_type_di_node, type_di_node, @@ -44,6 +45,7 @@ use crate::llvm::debuginfo::{ use crate::llvm::{self, Value}; mod create_scope_map; +mod di_builder; mod dwarf_const; mod gdb; pub(crate) mod metadata; @@ -181,9 +183,7 @@ impl<'ll> DebugInfoBuilderMethods for Builder<'_, 'll, '_> { } let di_builder = DIB(self.cx()); - let addr_expr = unsafe { - llvm::LLVMDIBuilderCreateExpression(di_builder, addr_ops.as_ptr(), addr_ops.len()) - }; + let addr_expr = di_builder.create_expression(&addr_ops); unsafe { llvm::LLVMDIBuilderInsertDeclareRecordAtEnd( di_builder, From 1db7d41665380cbe26639a9db50a6548805d929b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 4 Oct 2025 22:50:44 +1000 Subject: [PATCH 12/15] Extract `DIBuilderExt::create_static_variable` --- .../src/debuginfo/di_builder.rs | 39 ++++++++++++ .../src/debuginfo/metadata.rs | 61 ++++++++----------- 2 files changed, 64 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs index 33657a049ad4b..84a07da2d2d28 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs @@ -1,3 +1,7 @@ +use libc::c_uint; +use rustc_abi::Align; + +use crate::common::AsCCharPtr; use crate::llvm; use crate::llvm::debuginfo::DIBuilder; @@ -10,6 +14,41 @@ pub(crate) trait DIBuilderExt<'ll> { let this = self.as_di_builder(); unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) } } + + fn create_static_variable( + &self, + scope: Option<&'ll llvm::Metadata>, + name: &str, + linkage_name: &str, + file: &'ll llvm::Metadata, + line_number: c_uint, + ty: &'ll llvm::Metadata, + is_local_to_unit: bool, + val: &'ll llvm::Value, + decl: Option<&'ll llvm::Metadata>, + align: Option, + ) -> &'ll llvm::Metadata { + let this = self.as_di_builder(); + let align_in_bits = align.map_or(0, |align| align.bits() as u32); + + unsafe { + llvm::LLVMRustDIBuilderCreateStaticVariable( + this, + scope, + name.as_c_char_ptr(), + name.len(), + linkage_name.as_c_char_ptr(), + linkage_name.len(), + file, + line_number, + ty, + is_local_to_unit, + val, + decl, + align_in_bits, + ) + } + } } impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 014715dd4fda5..5535ebe65859e 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -34,9 +34,9 @@ use super::namespace::mangled_name_of_instance; use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name}; use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit}; use crate::common::{AsCCharPtr, CodegenCx}; -use crate::debuginfo::dwarf_const; use crate::debuginfo::metadata::type_map::build_type_with_children; use crate::debuginfo::utils::{WidePtrKind, wide_pointer_kind}; +use crate::debuginfo::{DIBuilderExt, dwarf_const}; use crate::llvm::debuginfo::{ DIBasicType, DIBuilder, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType, DebugEmissionKind, DebugNameTableKind, @@ -1410,23 +1410,18 @@ pub(crate) fn build_global_var_di_node<'ll>( let global_align = cx.align_of(variable_type); - unsafe { - llvm::LLVMRustDIBuilderCreateStaticVariable( - DIB(cx), - Some(var_scope), - var_name.as_c_char_ptr(), - var_name.len(), - linkage_name.as_c_char_ptr(), - linkage_name.len(), - file_metadata, - line_number, - type_di_node, - is_local_to_unit, - global, - None, - global_align.bits() as u32, - ); - } + DIB(cx).create_static_variable( + Some(var_scope), + var_name, + linkage_name, + file_metadata, + line_number, + type_di_node, + is_local_to_unit, + global, // (value) + None, // (decl) + Some(global_align), + ); } /// Generates LLVM debuginfo for a vtable. @@ -1643,25 +1638,19 @@ pub(crate) fn create_vtable_di_node<'ll, 'tcx>( let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref); - let linkage_name = ""; - unsafe { - llvm::LLVMRustDIBuilderCreateStaticVariable( - DIB(cx), - NO_SCOPE_METADATA, - vtable_name.as_c_char_ptr(), - vtable_name.len(), - linkage_name.as_c_char_ptr(), - linkage_name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - vtable_type_di_node, - true, - vtable, - None, - 0, - ); - } + DIB(cx).create_static_variable( + NO_SCOPE_METADATA, + &vtable_name, + "", // (linkage_name) + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + vtable_type_di_node, + true, // (is_local_to_unit) + vtable, // (value) + None, // (decl) + None::, + ); } /// Creates an "extension" of an existing `DIScope` into another file. From 1081d985510e74625190a0ca83d8156b270aaa19 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 4 Oct 2025 22:54:37 +1000 Subject: [PATCH 13/15] Use `LLVMDIBuilderCreateGlobalVariableExpression` Note that the code in `LLVMRustDIBuilderCreateStaticVariable` that tried to downcast `InitVal` appears to have been dead, because `llvm::ConstantInt` and `llvm::ConstantFP` are not subclasses of `llvm::GlobalVariable`. --- .../src/debuginfo/di_builder.rs | 27 ++++++++----- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 39 +++++++++---------- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 31 --------------- 3 files changed, 37 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs index 84a07da2d2d28..5d874631ca1ac 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/di_builder.rs @@ -1,9 +1,8 @@ use libc::c_uint; use rustc_abi::Align; -use crate::common::AsCCharPtr; -use crate::llvm; use crate::llvm::debuginfo::DIBuilder; +use crate::llvm::{self, ToLlvmBool}; /// Extension trait for defining safe wrappers and helper methods on /// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate. @@ -31,23 +30,33 @@ pub(crate) trait DIBuilderExt<'ll> { let this = self.as_di_builder(); let align_in_bits = align.map_or(0, |align| align.bits() as u32); - unsafe { - llvm::LLVMRustDIBuilderCreateStaticVariable( + // `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we + // gave it a null `Expr` pointer, so give it an empty expression + // instead, which is what the C++ `createGlobalVariableExpression` + // method would do if given a null `DIExpression` pointer. + let expr = self.create_expression(&[]); + + let global_var_expr = unsafe { + llvm::LLVMDIBuilderCreateGlobalVariableExpression( this, scope, - name.as_c_char_ptr(), + name.as_ptr(), name.len(), - linkage_name.as_c_char_ptr(), + linkage_name.as_ptr(), linkage_name.len(), file, line_number, ty, - is_local_to_unit, - val, + is_local_to_unit.to_llvm_bool(), + expr, decl, align_in_bits, ) - } + }; + + unsafe { llvm::LLVMGlobalSetMetadata(val, llvm::MD_dbg, global_var_expr) }; + + global_var_expr } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 67e8bc7062bd9..711cbe568562a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -22,9 +22,9 @@ use libc::{c_char, c_int, c_uchar, c_uint, c_ulonglong, c_void, size_t}; use super::RustString; use super::debuginfo::{ - DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, - DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, - DITemplateTypeParameter, DIType, DebugEmissionKind, DebugNameTableKind, + DIArray, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, DILocation, + DISPFlags, DIScope, DISubprogram, DITemplateTypeParameter, DIType, DebugEmissionKind, + DebugNameTableKind, }; use crate::llvm::MetadataKindId; use crate::{TryFromU32, llvm}; @@ -781,7 +781,6 @@ pub(crate) mod debuginfo { pub(crate) type DIDerivedType = DIType; pub(crate) type DICompositeType = DIDerivedType; pub(crate) type DIVariable = DIDescriptor; - pub(crate) type DIGlobalVariableExpression = DIDescriptor; pub(crate) type DIArray = DIDescriptor; pub(crate) type DIEnumerator = DIDescriptor; pub(crate) type DITemplateTypeParameter = DIDescriptor; @@ -1875,6 +1874,22 @@ unsafe extern "C" { Length: size_t, ) -> &'ll Metadata; + pub(crate) fn LLVMDIBuilderCreateGlobalVariableExpression<'ll>( + Builder: &DIBuilder<'ll>, + Scope: Option<&'ll Metadata>, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + Linkage: *const c_uchar, // See "PTR_LEN_STR". + LinkLen: size_t, + File: &'ll Metadata, + LineNo: c_uint, + Ty: &'ll Metadata, + LocalToUnit: llvm::Bool, + Expr: &'ll Metadata, + Decl: Option<&'ll Metadata>, + AlignInBits: u32, + ) -> &'ll Metadata; + pub(crate) fn LLVMDIBuilderInsertDeclareRecordAtEnd<'ll>( Builder: &DIBuilder<'ll>, Storage: &'ll Value, @@ -2214,22 +2229,6 @@ unsafe extern "C" { Ty: &'a DIType, ) -> &'a DIType; - pub(crate) fn LLVMRustDIBuilderCreateStaticVariable<'a>( - Builder: &DIBuilder<'a>, - Context: Option<&'a DIScope>, - Name: *const c_char, - NameLen: size_t, - LinkageName: *const c_char, - LinkageNameLen: size_t, - File: &'a DIFile, - LineNo: c_uint, - Ty: &'a DIType, - isLocalToUnit: bool, - Val: &'a Value, - Decl: Option<&'a DIDescriptor>, - AlignInBits: u32, - ) -> &'a DIGlobalVariableExpression; - pub(crate) fn LLVMRustDIBuilderCreateEnumerator<'a>( Builder: &DIBuilder<'a>, Name: *const c_char, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 3722f8d689e53..807df63cc8832 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1044,37 +1044,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantMemberType( fromRust(Flags), unwrapDI(Ty))); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStaticVariable( - LLVMDIBuilderRef Builder, LLVMMetadataRef Context, const char *Name, - size_t NameLen, const char *LinkageName, size_t LinkageNameLen, - LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, - bool IsLocalToUnit, LLVMValueRef V, LLVMMetadataRef Decl = nullptr, - uint32_t AlignInBits = 0) { - llvm::GlobalVariable *InitVal = cast(unwrap(V)); - - llvm::DIExpression *InitExpr = nullptr; - if (llvm::ConstantInt *IntVal = llvm::dyn_cast(InitVal)) { - InitExpr = unwrap(Builder)->createConstantValueExpression( - IntVal->getValue().getSExtValue()); - } else if (llvm::ConstantFP *FPVal = - llvm::dyn_cast(InitVal)) { - InitExpr = unwrap(Builder)->createConstantValueExpression( - FPVal->getValueAPF().bitcastToAPInt().getZExtValue()); - } - - llvm::DIGlobalVariableExpression *VarExpr = - unwrap(Builder)->createGlobalVariableExpression( - unwrapDI(Context), StringRef(Name, NameLen), - StringRef(LinkageName, LinkageNameLen), unwrapDI(File), - LineNo, unwrapDI(Ty), IsLocalToUnit, - /* isDefined */ true, InitExpr, unwrapDIPtr(Decl), - /* templateParams */ nullptr, AlignInBits); - - InitVal->setMetadata("dbg", VarExpr); - - return wrap(VarExpr); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerator(LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, const uint64_t Value[2], From 9ff52bf332e03b0f0d06f3a8d8a3719b7b62c475 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 13 Oct 2025 12:56:34 +1100 Subject: [PATCH 14/15] Clear `ChunkedBitSet` without reallocating --- compiler/rustc_index/src/bit_set.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index f7649c5f5c55e..d5a184c259319 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -585,8 +585,7 @@ impl ChunkedBitSet { } pub fn clear(&mut self) { - let domain_size = self.domain_size(); - *self = ChunkedBitSet::new_empty(domain_size); + self.chunks.fill_with(|| Chunk::Zeros); } #[cfg(test)] @@ -684,9 +683,7 @@ impl ChunkedBitSet { /// Sets all bits to true. pub fn insert_all(&mut self) { - for chunk in self.chunks.iter_mut() { - *chunk = Ones; - } + self.chunks.fill_with(|| Chunk::Ones); } /// Returns `true` if the set has changed. From e755d71855aa455cdc72e210e8caae2a63e3379e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 13 Oct 2025 09:29:21 +0200 Subject: [PATCH 15/15] Add a warning when running tests with the GCC backend and debug assertions are enabled --- src/bootstrap/src/core/build_steps/test.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 36cd4b24c5911..5fbedb045e409 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1942,6 +1942,17 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} ); crate::exit!(1); } + + if let CodegenBackendKind::Gcc = codegen_backend + && builder.config.rustc_debug_assertions + { + eprintln!( + r#"WARNING: Running tests with the GCC codegen backend while rustc debug assertions are enabled. This might lead to test failures. +Please disable assertions with `rust.debug-assertions = false`. + "# + ); + } + // Tells compiletest that we want to use this codegen in particular and to override // the default one. cmd.arg("--override-codegen-backend").arg(codegen_backend.name());