stabilize -Clinker-features=-lld on x64 linux

This stabilizes a subset of the `-Clinker-features` components on x64 linux:
the lld opt-out.

The opt-in is not stabilized, as interactions with other stable flags require
more internal work, but are not needed for stabilizing using rust-lld by default.

Similarly, since we only switch to rust-lld on x64 linux, the opt-out is
only stabilized there. Other targets still require `-Zunstable-options`
to use it.
This commit is contained in:
Rémy Rakic
2025-07-08 09:01:25 +00:00
parent aa52711543
commit 2e6d82c9c9
10 changed files with 70 additions and 20 deletions

View File

@@ -1379,7 +1379,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
} }
} }
let features = sess.opts.unstable_opts.linker_features; let features = sess.opts.cg.linker_features;
// linker and linker flavor specified via command line have precedence over what the target // linker and linker flavor specified via command line have precedence over what the target
// specification specifies // specification specifies

View File

@@ -402,7 +402,7 @@ impl LinkSelfContained {
} }
} }
/// The different values that `-Z linker-features` can take on the CLI: a list of individually /// The different values that `-C linker-features` can take on the CLI: a list of individually
/// enabled or disabled features used during linking. /// enabled or disabled features used during linking.
/// ///
/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be /// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
@@ -442,6 +442,39 @@ impl LinkerFeaturesCli {
_ => None, _ => None,
} }
} }
/// When *not* using `-Z unstable-options` on the CLI, ensure only stable linker features are
/// used, for the given `TargetTuple`. Returns `Ok` if no unstable variants are used.
/// The caller should ensure that e.g. `nightly_options::is_unstable_enabled()`
/// returns false.
pub(crate) fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
// `-C linker-features=-lld` is only stable on x64 linux.
let has_minus_lld = self.disabled.is_lld_enabled();
if has_minus_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
return Err(format!(
"`-C linker-features=-lld` is unstable on the `{target_tuple}` \
target. The `-Z unstable-options` flag must also be passed to use it on this target",
));
}
// Any `+lld` or non-lld feature used is unstable, and that's an error.
let unstable_enabled = self.enabled;
let unstable_disabled = self.disabled - LinkerFeatures::LLD;
if !unstable_enabled.union(unstable_disabled).is_empty() {
let unstable_features: Vec<_> = unstable_enabled
.iter()
.map(|f| format!("+{}", f.as_str().unwrap()))
.chain(unstable_disabled.iter().map(|f| format!("-{}", f.as_str().unwrap())))
.collect();
return Err(format!(
"`-C linker-features={}` is unstable, and also requires the \
`-Z unstable-options` flag to be used",
unstable_features.join(","),
));
}
Ok(())
}
} }
/// Used with `-Z assert-incr-state`. /// Used with `-Z assert-incr-state`.
@@ -2638,9 +2671,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
} }
} }
if !nightly_options::is_unstable_enabled(matches) let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
&& cg.force_frame_pointers == FramePointer::NonLeaf if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
{
early_dcx.early_fatal( early_dcx.early_fatal(
"`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \ "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
and a nightly compiler", and a nightly compiler",
@@ -2650,7 +2682,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
// For testing purposes, until we have more feedback about these options: ensure `-Z // For testing purposes, until we have more feedback about these options: ensure `-Z
// unstable-options` is required when using the unstable `-C link-self-contained` and `-C // unstable-options` is required when using the unstable `-C link-self-contained` and `-C
// linker-flavor` options. // linker-flavor` options.
if !nightly_options::is_unstable_enabled(matches) { if !unstable_options_enabled {
let uses_unstable_self_contained_option = let uses_unstable_self_contained_option =
cg.link_self_contained.are_unstable_variants_set(); cg.link_self_contained.are_unstable_variants_set();
if uses_unstable_self_contained_option { if uses_unstable_self_contained_option {
@@ -2706,6 +2738,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let debuginfo = select_debuginfo(matches, &cg); let debuginfo = select_debuginfo(matches, &cg);
let debuginfo_compression = unstable_opts.debuginfo_compression; let debuginfo_compression = unstable_opts.debuginfo_compression;
if !unstable_options_enabled {
if let Err(error) = cg.linker_features.check_unstable_variants(&target_triple) {
early_dcx.early_fatal(error);
}
}
let crate_name = matches.opt_str("crate-name"); let crate_name = matches.opt_str("crate-name");
let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref()); let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
// Parse any `-l` flags, which link to native libraries. // Parse any `-l` flags, which link to native libraries.

View File

@@ -2015,6 +2015,8 @@ options! {
on a C toolchain or linker installed in the system"), on a C toolchain or linker installed in the system"),
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"system linker to link outputs with"), "system linker to link outputs with"),
linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
"a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED], linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
"linker flavor"), "linker flavor"),
linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled, linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
@@ -2307,8 +2309,6 @@ options! {
"link native libraries in the linker invocation (default: yes)"), "link native libraries in the linker invocation (default: yes)"),
link_only: bool = (false, parse_bool, [TRACKED], link_only: bool = (false, parse_bool, [TRACKED],
"link the `.rlink` file generated by `-Z no-link` (default: no)"), "link the `.rlink` file generated by `-Z no-link` (default: no)"),
linker_features: LinkerFeaturesCli = (LinkerFeaturesCli::default(), parse_linker_features, [UNTRACKED],
"a comma-separated list of linker features to enable (+) or disable (-): `lld`"),
lint_llvm_ir: bool = (false, parse_bool, [TRACKED], lint_llvm_ir: bool = (false, parse_bool, [TRACKED],
"lint LLVM IR (default: no)"), "lint LLVM IR (default: no)"),
lint_mir: bool = (false, parse_bool, [UNTRACKED], lint_mir: bool = (false, parse_bool, [UNTRACKED],

View File

@@ -725,7 +725,7 @@ impl ToJson for LinkSelfContainedComponents {
} }
bitflags::bitflags! { bitflags::bitflags! {
/// The `-Z linker-features` components that can individually be enabled or disabled. /// The `-C linker-features` components that can individually be enabled or disabled.
/// ///
/// They are feature flags intended to be a more flexible mechanism than linker flavors, and /// They are feature flags intended to be a more flexible mechanism than linker flavors, and
/// also to prevent a combinatorial explosion of flavors whenever a new linker feature is /// also to prevent a combinatorial explosion of flavors whenever a new linker feature is
@@ -756,7 +756,7 @@ bitflags::bitflags! {
rustc_data_structures::external_bitflags_debug! { LinkerFeatures } rustc_data_structures::external_bitflags_debug! { LinkerFeatures }
impl LinkerFeatures { impl LinkerFeatures {
/// Parses a single `-Z linker-features` well-known feature, not a set of flags. /// Parses a single `-C linker-features` well-known feature, not a set of flags.
pub fn from_str(s: &str) -> Option<LinkerFeatures> { pub fn from_str(s: &str) -> Option<LinkerFeatures> {
Some(match s { Some(match s {
"cc" => LinkerFeatures::CC, "cc" => LinkerFeatures::CC,
@@ -765,6 +765,17 @@ impl LinkerFeatures {
}) })
} }
/// Return the linker feature name, as would be passed on the CLI.
///
/// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags).
pub fn as_str(self) -> Option<&'static str> {
Some(match self {
LinkerFeatures::CC => "cc",
LinkerFeatures::LLD => "lld",
_ => return None,
})
}
/// Returns whether the `lld` linker feature is enabled. /// Returns whether the `lld` linker feature is enabled.
pub fn is_lld_enabled(self) -> bool { pub fn is_lld_enabled(self) -> bool {
self.contains(LinkerFeatures::LLD) self.contains(LinkerFeatures::LLD)

View File

@@ -26,7 +26,7 @@ fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare
run_in_tmpdir(|| { run_in_tmpdir(|| {
let mut rustc = Rustc::new(); let mut rustc = Rustc::new();
rustc rustc
.arg("-Zlinker-features=+lld") .arg("-Clinker-features=+lld")
.arg("-Clink-self-contained=+linker") .arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options") .arg("-Zunstable-options")
.arg("-Cdebuginfo=full") .arg("-Cdebuginfo=full")

View File

@@ -23,7 +23,8 @@ fn main() {
rustc() rustc()
.crate_type("cdylib") .crate_type("cdylib")
.target("custom-target.json") .target("custom-target.json")
.arg("-Zlinker-features=-lld") .arg("-Clinker-features=-lld")
.arg("-Zunstable-options")
.input("lib.rs"), .input("lib.rs"),
); );
} }

View File

@@ -10,7 +10,7 @@ use run_make_support::rustc;
fn main() { fn main() {
rustc() rustc()
.input("main.rs") .input("main.rs")
.arg("-Zlinker-features=+lld") .arg("-Clinker-features=+lld")
.arg("-Clink-self-contained=+linker") .arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options") .arg("-Zunstable-options")
.link_arg("-Tscript.t") .link_arg("-Tscript.t")

View File

@@ -12,5 +12,5 @@ fn main() {
assert_rustc_uses_lld(rustc().input("main.rs")); assert_rustc_uses_lld(rustc().input("main.rs"));
// But it can still be disabled by turning the linker feature off. // But it can still be disabled by turning the linker feature off.
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs")); assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
} }

View File

@@ -16,5 +16,5 @@ fn main() {
assert_rustc_uses_lld(rustc().input("main.rs")); assert_rustc_uses_lld(rustc().input("main.rs"));
// But it can still be disabled by turning the linker feature off. // But it can still be disabled by turning the linker feature off.
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs")); assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
} }

View File

@@ -12,14 +12,14 @@ fn main() {
// asking the linker to display its version number with a link-arg. // asking the linker to display its version number with a link-arg.
assert_rustc_uses_lld( assert_rustc_uses_lld(
rustc() rustc()
.arg("-Zlinker-features=+lld") .arg("-Clinker-features=+lld")
.arg("-Clink-self-contained=+linker") .arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options") .arg("-Zunstable-options")
.input("main.rs"), .input("main.rs"),
); );
// It should not be used when we explicitly opt out of lld. // It should not be used when we explicitly opt out of lld.
assert_rustc_doesnt_use_lld(rustc().arg("-Zlinker-features=-lld").input("main.rs")); assert_rustc_doesnt_use_lld(rustc().arg("-Clinker-features=-lld").input("main.rs"));
// While we're here, also check that the last linker feature flag "wins" when passed multiple // While we're here, also check that the last linker feature flag "wins" when passed multiple
// times to rustc. // times to rustc.
@@ -27,9 +27,9 @@ fn main() {
rustc() rustc()
.arg("-Clink-self-contained=+linker") .arg("-Clink-self-contained=+linker")
.arg("-Zunstable-options") .arg("-Zunstable-options")
.arg("-Zlinker-features=-lld") .arg("-Clinker-features=-lld")
.arg("-Zlinker-features=+lld") .arg("-Clinker-features=+lld")
.arg("-Zlinker-features=-lld,+lld") .arg("-Clinker-features=-lld,+lld")
.input("main.rs"), .input("main.rs"),
); );
} }