about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRémy Rakic <remy.rakic+github@gmail.com>2025-07-08 09:01:25 +0000
committerRémy Rakic <remy.rakic+github@gmail.com>2025-07-08 09:04:21 +0000
commit2e6d82c9c96348a2f7dafd1a3337287408fc9751 (patch)
tree407f868c43b74b5fcdca88329434e8125561934b
parentaa527115432df082f3c9e4d2459acb7bb02ed5a6 (diff)
downloadrust-2e6d82c9c96348a2f7dafd1a3337287408fc9751.tar.gz
rust-2e6d82c9c96348a2f7dafd1a3337287408fc9751.zip
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.
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs2
-rw-r--r--compiler/rustc_session/src/config.rs48
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_target/src/spec/mod.rs15
-rw-r--r--tests/run-make/compressed-debuginfo-zstd/rmake.rs2
-rw-r--r--tests/run-make/rust-lld-custom-target/rmake.rs3
-rw-r--r--tests/run-make/rust-lld-link-script-provide/rmake.rs2
-rw-r--r--tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs2
-rw-r--r--tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs2
-rw-r--r--tests/run-make/rust-lld/rmake.rs10
10 files changed, 70 insertions, 20 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 343cb0eeca9..34328687e3f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -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
     // specification specifies
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 4627c2978fc..76969a0c409 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -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.
 ///
 /// 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,
         }
     }
+
+    /// 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`.
@@ -2638,9 +2671,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         }
     }
 
-    if !nightly_options::is_unstable_enabled(matches)
-        && cg.force_frame_pointers == FramePointer::NonLeaf
-    {
+    let unstable_options_enabled = nightly_options::is_unstable_enabled(matches);
+    if !unstable_options_enabled && cg.force_frame_pointers == FramePointer::NonLeaf {
         early_dcx.early_fatal(
             "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
                 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
     // unstable-options` is required when using the unstable `-C link-self-contained` and `-C
     // linker-flavor` options.
-    if !nightly_options::is_unstable_enabled(matches) {
+    if !unstable_options_enabled {
         let uses_unstable_self_contained_option =
             cg.link_self_contained.are_unstable_variants_set();
         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_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 unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
     // Parse any `-l` flags, which link to native libraries.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index ecd82c0cc01..626262c8442 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2015,6 +2015,8 @@ options! {
         on a C toolchain or linker installed in the system"),
     linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "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"),
     linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
@@ -2307,8 +2309,6 @@ options! {
         "link native libraries in the linker invocation (default: yes)"),
     link_only: bool = (false, parse_bool, [TRACKED],
         "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 (default: no)"),
     lint_mir: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 5346b206a17..4bc0d88a910 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -725,7 +725,7 @@ impl ToJson for LinkSelfContainedComponents {
 }
 
 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
     /// 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 }
 
 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> {
         Some(match s {
             "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.
     pub fn is_lld_enabled(self) -> bool {
         self.contains(LinkerFeatures::LLD)
diff --git a/tests/run-make/compressed-debuginfo-zstd/rmake.rs b/tests/run-make/compressed-debuginfo-zstd/rmake.rs
index cd8cf223047..8d7e5c089da 100644
--- a/tests/run-make/compressed-debuginfo-zstd/rmake.rs
+++ b/tests/run-make/compressed-debuginfo-zstd/rmake.rs
@@ -26,7 +26,7 @@ fn prepare_and_check<F: FnOnce(&mut Rustc) -> &mut Rustc>(to_find: &str, prepare
     run_in_tmpdir(|| {
         let mut rustc = Rustc::new();
         rustc
-            .arg("-Zlinker-features=+lld")
+            .arg("-Clinker-features=+lld")
             .arg("-Clink-self-contained=+linker")
             .arg("-Zunstable-options")
             .arg("-Cdebuginfo=full")
diff --git a/tests/run-make/rust-lld-custom-target/rmake.rs b/tests/run-make/rust-lld-custom-target/rmake.rs
index e2b065a10b1..90ba424ffe9 100644
--- a/tests/run-make/rust-lld-custom-target/rmake.rs
+++ b/tests/run-make/rust-lld-custom-target/rmake.rs
@@ -23,7 +23,8 @@ fn main() {
         rustc()
             .crate_type("cdylib")
             .target("custom-target.json")
-            .arg("-Zlinker-features=-lld")
+            .arg("-Clinker-features=-lld")
+            .arg("-Zunstable-options")
             .input("lib.rs"),
     );
 }
diff --git a/tests/run-make/rust-lld-link-script-provide/rmake.rs b/tests/run-make/rust-lld-link-script-provide/rmake.rs
index e78a411bc15..c637dff9038 100644
--- a/tests/run-make/rust-lld-link-script-provide/rmake.rs
+++ b/tests/run-make/rust-lld-link-script-provide/rmake.rs
@@ -10,7 +10,7 @@ use run_make_support::rustc;
 fn main() {
     rustc()
         .input("main.rs")
-        .arg("-Zlinker-features=+lld")
+        .arg("-Clinker-features=+lld")
         .arg("-Clink-self-contained=+linker")
         .arg("-Zunstable-options")
         .link_arg("-Tscript.t")
diff --git a/tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs b/tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs
index c26f82b7d37..c315d36a39d 100644
--- a/tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs
+++ b/tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist/rmake.rs
@@ -12,5 +12,5 @@ fn main() {
     assert_rustc_uses_lld(rustc().input("main.rs"));
 
     // 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"));
 }
diff --git a/tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs b/tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs
index e71a47f11e2..00415d27aaf 100644
--- a/tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs
+++ b/tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs
@@ -16,5 +16,5 @@ fn main() {
     assert_rustc_uses_lld(rustc().input("main.rs"));
 
     // 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"));
 }
diff --git a/tests/run-make/rust-lld/rmake.rs b/tests/run-make/rust-lld/rmake.rs
index 9470f5d0be1..2b914f19ac0 100644
--- a/tests/run-make/rust-lld/rmake.rs
+++ b/tests/run-make/rust-lld/rmake.rs
@@ -12,14 +12,14 @@ fn main() {
     // asking the linker to display its version number with a link-arg.
     assert_rustc_uses_lld(
         rustc()
-            .arg("-Zlinker-features=+lld")
+            .arg("-Clinker-features=+lld")
             .arg("-Clink-self-contained=+linker")
             .arg("-Zunstable-options")
             .input("main.rs"),
     );
 
     // 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
     // times to rustc.
@@ -27,9 +27,9 @@ fn main() {
         rustc()
             .arg("-Clink-self-contained=+linker")
             .arg("-Zunstable-options")
-            .arg("-Zlinker-features=-lld")
-            .arg("-Zlinker-features=+lld")
-            .arg("-Zlinker-features=-lld,+lld")
+            .arg("-Clinker-features=-lld")
+            .arg("-Clinker-features=+lld")
+            .arg("-Clinker-features=-lld,+lld")
             .input("main.rs"),
     );
 }