Skip to content

Use lld by default on x86_64-unknown-linux-gnu stable #140525

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 9, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 1 addition & 30 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
@@ -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
@@ -3327,35 +3327,6 @@ fn add_lld_args(
// this, `wasm-component-ld`, which is overridden if this option is passed.
if !sess.target.is_like_wasm {
cmd.cc_arg("-fuse-ld=lld");

// On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some
// section garbage-collection features. For example, the somewhat popular `linkme` crate and
// its dependents rely in practice on this difference: when using lld, they need `-z
// nostart-stop-gc` to prevent encapsulation symbols and sections from being
// garbage-collected.
//
// More information about all this can be found in:
// - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order
// - https://lld.llvm.org/ELF/start-stop-gc
//
// So when using lld, we restore, for now, the traditional behavior to help migration, but
// will remove it in the future.
// Since this only disables an optimization, it shouldn't create issues, but is in theory
// slightly suboptimal. However, it:
// - doesn't have any visible impact on our benchmarks
// - reduces the need to disable lld for the crates that depend on this
//
// Note that lld can detect some cases where this difference is relied on, and emits a
// dedicated error to add this link arg. We could make use of this error to emit an FCW. As
// of writing this, we don't do it, because lld is already enabled by default on nightly
// without this mitigation: no working project would see the FCW, so we do this to help
// stabilization.
//
// FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the
// future.
if sess.target.llvm_target == "x86_64-unknown-linux-gnu" {
cmd.link_arg("-znostart-stop-gc");
}
}

if !flavor.is_gnu() {
99 changes: 77 additions & 22 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
@@ -370,12 +370,34 @@ impl LinkSelfContained {
}

/// To help checking CLI usage while some of the values are unstable: returns whether one of the
/// components was set individually. This would also require the `-Zunstable-options` flag, to
/// be allowed.
fn are_unstable_variants_set(&self) -> bool {
let any_component_set =
!self.enabled_components.is_empty() || !self.disabled_components.is_empty();
self.explicitly_set.is_none() && any_component_set
/// unstable components was set individually, for the given `TargetTuple`. This would also
/// require the `-Zunstable-options` flag, to be allowed.
fn check_unstable_variants(&self, target_tuple: &TargetTuple) -> Result<(), String> {
if self.explicitly_set.is_some() {
return Ok(());
}

// `-C link-self-contained=-linker` is only stable on x64 linux.
let has_minus_linker = self.disabled_components.is_linker_enabled();
if has_minus_linker && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
return Err(format!(
"`-C link-self-contained=-linker` is unstable on the `{target_tuple}` \
target. The `-Z unstable-options` flag must also be passed to use it on this target",
));
}

// Any `+linker` or other component used is unstable, and that's an error.
let unstable_enabled = self.enabled_components;
let unstable_disabled = self.disabled_components - LinkSelfContainedComponents::LINKER;
if !unstable_enabled.union(unstable_disabled).is_empty() {
return Err(String::from(
"only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` \
are stable, the `-Z unstable-options` flag must also be passed to use \
the unstable values",
));
}

Ok(())
}

/// Returns whether the self-contained linker component was enabled on the CLI, using the
@@ -402,7 +424,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 +464,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,26 +2693,21 @@ 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",
)
}

// 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) {
let uses_unstable_self_contained_option =
cg.link_self_contained.are_unstable_variants_set();
if uses_unstable_self_contained_option {
early_dcx.early_fatal(
"only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
the `-Z unstable-options` flag must also be passed to use the unstable values",
);
let target_triple = parse_target_triple(early_dcx, matches);

// Ensure `-Z unstable-options` is required when using the unstable `-C link-self-contained` and
// `-C linker-flavor` options.
if !unstable_options_enabled {
if let Err(error) = cg.link_self_contained.check_unstable_variants(&target_triple) {
early_dcx.early_fatal(error);
}

if let Some(flavor) = cg.linker_flavor {
@@ -2697,7 +2747,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M

let cg = cg;

let target_triple = parse_target_triple(early_dcx, matches);
let opt_level = parse_opt_level(early_dcx, matches, &cg);
// The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
// to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
@@ -2706,6 +2755,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.
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
@@ -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],
15 changes: 13 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 1 addition & 3 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
@@ -1369,9 +1369,7 @@ pub fn rustc_cargo_env(
}

// Enable rustc's env var for `rust-lld` when requested.
if builder.config.lld_enabled
&& (builder.config.channel == "dev" || builder.config.channel == "nightly")
{
if builder.config.lld_enabled {
cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
}

20 changes: 16 additions & 4 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
@@ -262,7 +262,13 @@ impl Step for Cargotest {
.args(builder.config.test_args())
.env("RUSTC", builder.rustc(compiler))
.env("RUSTDOC", builder.rustdoc(compiler));
add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No);
add_rustdoc_cargo_linker_args(
&mut cmd,
builder,
compiler.host,
LldThreads::No,
compiler.stage,
);
cmd.delay_failure().run(builder);
}
}
@@ -857,7 +863,7 @@ impl Step for RustdocTheme {
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
.env("RUSTC_BOOTSTRAP", "1");
cmd.args(linker_args(builder, self.compiler.host, LldThreads::No));
cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage));

cmd.delay_failure().run(builder);
}
@@ -1033,7 +1039,13 @@ impl Step for RustdocGUI {
cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
.env("RUSTC", builder.rustc(self.compiler));

add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No);
add_rustdoc_cargo_linker_args(
&mut cmd,
builder,
self.compiler.host,
LldThreads::No,
self.compiler.stage,
);

for path in &builder.paths {
if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
@@ -1812,7 +1824,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
}

let mut hostflags = flags.clone();
hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No));
hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage));

let mut targetflags = flags;

15 changes: 10 additions & 5 deletions src/bootstrap/src/core/builder/cargo.rs
Original file line number Diff line number Diff line change
@@ -115,7 +115,7 @@ impl Cargo {
// No need to configure the target linker for these command types.
Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {}
_ => {
cargo.configure_linker(builder);
cargo.configure_linker(builder, mode);
}
}

@@ -209,7 +209,7 @@ impl Cargo {

// FIXME(onur-ozkan): Add coverage to make sure modifications to this function
// doesn't cause cache invalidations (e.g., #130108).
fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
fn configure_linker(&mut self, builder: &Builder<'_>, mode: Mode) -> &mut Cargo {
let target = self.target;
let compiler = self.compiler;

@@ -264,7 +264,12 @@ impl Cargo {
}
}

for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
// We use the snapshot compiler when building host code (build scripts/proc macros) of
// `Mode::Std` tools, so we need to determine the current stage here to pass the proper
// linker args (e.g. -C vs -Z).
// This should stay synchronized with the [cargo] function.
let host_stage = if mode == Mode::Std { 0 } else { compiler.stage };
for arg in linker_args(builder, compiler.host, LldThreads::Yes, host_stage) {
self.hostflags.arg(&arg);
}

@@ -274,10 +279,10 @@ impl Cargo {
}
// We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
// `linker_args` here.
for flag in linker_flags(builder, target, LldThreads::Yes) {
for flag in linker_flags(builder, target, LldThreads::Yes, compiler.stage) {
self.rustflags.arg(&flag);
}
for arg in linker_args(builder, target, LldThreads::Yes) {
for arg in linker_args(builder, target, LldThreads::Yes, compiler.stage) {
self.rustdocflags.arg(&arg);
}

2 changes: 1 addition & 1 deletion src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
@@ -1599,7 +1599,7 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
cmd.arg("-Dwarnings");
}
cmd.arg("-Znormalize-docs");
cmd.args(linker_args(self, compiler.host, LldThreads::Yes));
cmd.args(linker_args(self, compiler.host, LldThreads::Yes, compiler.stage));
cmd
}

5 changes: 1 addition & 4 deletions src/bootstrap/src/core/config/toml/rust.rs
Original file line number Diff line number Diff line change
@@ -619,7 +619,6 @@ impl Config {
// 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
// - on the `dev` and `nightly` channels
// - 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
@@ -628,9 +627,7 @@ impl Config {
// 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`
if self.host_target.triple == "x86_64-unknown-linux-gnu"
&& self.hosts == [self.host_target]
&& (self.channel == "dev" || self.channel == "nightly")
if self.host_target.triple == "x86_64-unknown-linux-gnu" && self.hosts == [self.host_target]
{
let no_llvm_config = self
.target_config
25 changes: 19 additions & 6 deletions src/bootstrap/src/utils/helpers.rs
Original file line number Diff line number Diff line change
@@ -404,8 +404,9 @@ pub fn linker_args(
builder: &Builder<'_>,
target: TargetSelection,
lld_threads: LldThreads,
stage: u32,
) -> Vec<String> {
let mut args = linker_flags(builder, target, lld_threads);
let mut args = linker_flags(builder, target, lld_threads, stage);

if let Some(linker) = builder.linker(target) {
args.push(format!("-Clinker={}", linker.display()));
@@ -420,19 +421,30 @@ pub fn linker_flags(
builder: &Builder<'_>,
target: TargetSelection,
lld_threads: LldThreads,
stage: u32,
) -> Vec<String> {
let mut args = vec![];
if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() {
match builder.config.lld_mode {
LldMode::External => {
args.push("-Zlinker-features=+lld".to_string());
// FIXME(kobzol): remove this flag once MCP510 gets stabilized
// cfg(bootstrap) - remove the stage 0 check after updating the bootstrap compiler:
// `-Clinker-features` has been stabilized.
if stage == 0 {
args.push("-Zlinker-features=+lld".to_string());
} else {
args.push("-Clinker-features=+lld".to_string());
}
args.push("-Zunstable-options".to_string());
}
LldMode::SelfContained => {
args.push("-Zlinker-features=+lld".to_string());
// cfg(bootstrap) - remove the stage 0 check after updating the bootstrap compiler:
// `-Clinker-features` has been stabilized.
if stage == 0 {
args.push("-Zlinker-features=+lld".to_string());
} else {
args.push("-Clinker-features=+lld".to_string());
}
args.push("-Clink-self-contained=+linker".to_string());
// FIXME(kobzol): remove this flag once MCP510 gets stabilized
args.push("-Zunstable-options".to_string());
}
LldMode::Unused => unreachable!(),
@@ -453,8 +465,9 @@ pub fn add_rustdoc_cargo_linker_args(
builder: &Builder<'_>,
target: TargetSelection,
lld_threads: LldThreads,
stage: u32,
) {
let args = linker_args(builder, target, lld_threads);
let args = linker_args(builder, target, lld_threads, stage);
let mut flags = cmd
.get_envs()
.find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None })
59 changes: 55 additions & 4 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
@@ -235,15 +235,33 @@ coverage measurement. Its use is not recommended.

## link-self-contained

On `windows-gnu`, `linux-musl`, and `wasi` targets, this flag controls whether the
linker will use libraries and objects shipped with Rust instead of those in the system.
It takes one of the following values:
This flag controls whether the linker will use libraries and objects shipped with Rust instead of
those in the system. It also controls which binary is used for the linker itself. This allows
overriding cases when detection fails or the user wants to use shipped libraries.

You can enable or disable the usage of any self-contained components using one of the following values:

* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools.
* `y`, `yes`, `on`, `true`: use only libraries/objects shipped with Rust.
* `n`, `no`, `off` or `false`: rely on the user or the linker to provide non-Rust libraries/objects.

This allows overriding cases when detection fails or user wants to use shipped libraries.
It is also possible to enable or disable specific self-contained components in a more granular way.
You can pass a comma-separated list of self-contained components, individually enabled
(`+component`) or disabled (`-component`).

Currently, only the `linker` granular option is stabilized, and only on the `x86_64-unknown-linux-gnu` target:
- `linker`: toggle the usage of self-contained linker binaries (linker, dlltool, and their necessary libraries)

Note that only the `-linker` opt-out is stable on the `x86_64-unknown-linux-gnu` target: `+linker` is
already the default on this target.

#### Implementation notes

On the `x86_64-unknown-linux-gnu` target, when using the default linker flavor (using `cc` as the
linker driver) and linker features (to try using `lld`), `rustc` will try to use the self-contained
linker by passing a `-B /path/to/sysroot/` link argument to the driver to find `rust-lld` in the
sysroot. For backwards-compatibility, and to limit name and `PATH` collisions, this is done using a
shim executable (the `lld-wrapper` tool) that forwards execution to the `rust-lld` executable itself.

## linker

@@ -256,6 +274,39 @@ Note that on Unix-like targets (for example, `*-unknown-linux-gnu` or `*-unknown
the C compiler (for example `cc` or `clang`) is used as the "linker" here, serving as a linker driver.
It will invoke the actual linker with all the necessary flags to be able to link against the system libraries like libc.

## linker-features

The `-Clinker-features` flag allows enabling or disabling specific features used during linking.

These feature flags are a flexible extension mechanism that is complementary to linker flavors,
designed to avoid the combinatorial explosion of having to create a new set of flavors for each
linker feature we'd want to use.

The flag accepts a comma-separated list of features, individually enabled (`+feature`) or disabled
(`-feature`).

Currently only one is stable, and only on the `x86_64-unknown-linux-gnu` target:
- `lld`: to toggle trying to use the lld linker, either the system-installed binary, or the self-contained
`rust-lld` linker (via the [`-Clink-self-contained=+linker`](#link-self-contained) flag).

For example, use:
- `-Clinker-features=+lld` to opt into using the `lld` linker, when possible (see the Implementation notes below)
- `-Clinker-features=-lld` to opt out instead, for targets where it is configured as the default linker

Note that only the `-lld` opt-out is stable on the `x86_64-unknown-linux-gnu` target: `+lld` is
already the default on this target.

#### Implementation notes

On the `x86_64-unknown-linux-gnu` target, when using the default linker flavor (using `cc` as the
linker driver), `rustc` will try to use lld by passing a `-fuse-ld=lld` link argument to the driver.
`rustc` will also try to detect if that _causes_ an error during linking (for example, if GCC is too
old to understand the flag, and returns an error) and will then retry linking without this argument,
as a fallback.

If the user _also_ passes a `-Clink-arg=-fuse-ld=$value`, both will be given to the linker
driver but the user's will be passed last, and would generally have priority over `rustc`'s.

## linker-flavor

This flag controls the linker flavor used by `rustc`. If a linker is given with
8 changes: 4 additions & 4 deletions src/doc/unstable-book/src/compiler-flags/codegen-options.md
Original file line number Diff line number Diff line change
@@ -51,10 +51,10 @@ instead of those in the system. The stable boolean values for this flag are coar
- `mingw`: other MinGW libs and Windows import libs

Out of the above self-contained linking components, `linker` is the only one currently implemented
(beyond parsing the CLI options).
(beyond parsing the CLI options) and stabilized.

It refers to the LLD linker, built from the same LLVM revision used by rustc (named `rust-lld` to
avoid naming conflicts), that is distributed via `rustup` with the compiler (and is used by default
for the wasm targets). One can also opt-in to use it by combining this flag with an appropriate
linker flavor: for example, `-Clinker-flavor=gnu-lld-cc -Clink-self-contained=+linker` will use the
toolchain's `rust-lld` as the linker.
for the wasm targets). One can also opt into using it by combining this flag with the appropriate
linker feature: for example, `-Clinker-features=+lld -Clink-self-contained=+linker` will use the
toolchain's `rust-lld` as the linker instead of the system's lld with `-Clinker-features=+lld` only.
35 changes: 0 additions & 35 deletions src/doc/unstable-book/src/compiler-flags/linker-features.md

This file was deleted.

3 changes: 3 additions & 0 deletions src/tools/opt-dist/src/tests.rs
Original file line number Diff line number Diff line change
@@ -106,7 +106,10 @@ llvm-config = "{llvm_config}"
"tests/incremental",
"tests/mir-opt",
"tests/pretty",
// Make sure that we don't use too new GLIBC symbols on x64
"tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu",
// Make sure that we use LLD by default on x64
"tests/run-make/rust-lld-x86_64-unknown-linux-gnu-dist",
"tests/ui",
"tests/crashes",
];
2 changes: 1 addition & 1 deletion tests/run-make/compressed-debuginfo-zstd/rmake.rs
Original file line number Diff line number Diff line change
@@ -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")
1 change: 0 additions & 1 deletion tests/run-make/rust-lld-by-default-beta-stable/main.rs

This file was deleted.

14 changes: 0 additions & 14 deletions tests/run-make/rust-lld-by-default-beta-stable/rmake.rs

This file was deleted.

3 changes: 2 additions & 1 deletion tests/run-make/rust-lld-custom-target/rmake.rs
Original file line number Diff line number Diff line change
@@ -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"),
);
}
2 changes: 1 addition & 1 deletion tests/run-make/rust-lld-link-script-provide/rmake.rs
Original file line number Diff line number Diff line change
@@ -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")
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu` on the nightly
// channel, and that it can also be turned off with a CLI flag.
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`
// dist artifacts and that it can also be turned off with a CLI flag.

//@ needs-rust-lld
//@ ignore-beta
//@ ignore-stable
//@ only-dist
//@ only-x86_64-unknown-linux-gnu

use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

fn main() {
// A regular compilation should use rust-lld by default. We'll check that by asking the linker
// to display its version number with a link-arg.
// A regular compilation should use rust-lld by default.
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"));
}
5 changes: 5 additions & 0 deletions tests/run-make/rust-lld-x86_64-unknown-linux-gnu/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
// target.
// See https://github.com/rust-lang/compiler-team/issues/510 for more info

fn main() {}
20 changes: 20 additions & 0 deletions tests/run-make/rust-lld-x86_64-unknown-linux-gnu/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`
// and that it can also be turned off with a CLI flag.
//
// This version of the test checks that LLD is used by default when LLD is enabled in the
// toolchain. There is a separate test that checks that LLD is used for dist artifacts
// unconditionally.

//@ needs-rust-lld
//@ only-x86_64-unknown-linux-gnu

use run_make_support::linker::{assert_rustc_doesnt_use_lld, assert_rustc_uses_lld};
use run_make_support::rustc;

fn main() {
// A regular compilation should use rust-lld by default.
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("-Clinker-features=-lld").input("main.rs"));
}
18 changes: 10 additions & 8 deletions tests/run-make/rust-lld/rmake.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Test linking using `cc` with `rust-lld`, using the unstable CLI described in MCP 510
// see https://github.com/rust-lang/compiler-team/issues/510 for more info
// Test linking using `cc` with `rust-lld`, using the `-Clinker-features` and
// `-Clink-self-contained` CLI flags.

//@ needs-rust-lld
//@ ignore-s390x lld does not yet support s390x as target
@@ -12,24 +12,26 @@ 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")
.arg("-Zunstable-options") // the opt-ins are unstable
.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").arg("-Zunstable-options").input("main.rs"),
);

// While we're here, also check that the last linker feature flag "wins" when passed multiple
// times to rustc.
assert_rustc_uses_lld(
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"),
);
}
1 change: 0 additions & 1 deletion tests/ui/linking/link-self-contained-consistency.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Checks that self-contained linking components cannot be both enabled and disabled at the same
// time on the CLI.

//@ check-fail
//@ revisions: one many
//@ [one] compile-flags: -Clink-self-contained=-linker -Clink-self-contained=+linker -Zunstable-options
//@ [many] compile-flags: -Clink-self-contained=+linker,+crto -Clink-self-contained=-linker,-crto -Zunstable-options
18 changes: 18 additions & 0 deletions tests/ui/linking/link-self-contained-linker-disallowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Check that only `-C link-self-contained=-linker` is stable on x64 linux. Any other value or
// target, needs `-Z unstable-options`.

// ignore-tidy-linelength

//@ revisions: unstable_target_positive unstable_target_negative unstable_positive
//@ [unstable_target_negative] compile-flags: --target=x86_64-unknown-linux-musl -C link-self-contained=-linker --crate-type=rlib
//@ [unstable_target_negative] needs-llvm-components: x86
//@ [unstable_target_positive] compile-flags: --target=x86_64-unknown-linux-musl -C link-self-contained=+linker --crate-type=rlib
//@ [unstable_target_positive] needs-llvm-components: x86
//@ [unstable_positive] compile-flags: --target=x86_64-unknown-linux-gnu -C link-self-contained=+linker --crate-type=rlib
//@ [unstable_positive] needs-llvm-components: x86

#![feature(no_core)]
#![no_core]

//[unstable_target_negative]~? ERROR `-C link-self-contained=-linker` is unstable on the `x86_64-unknown-linux-musl` target
//[unstable_target_positive,unstable_positive]~? ERROR only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: `-C link-self-contained=-linker` is unstable on the `x86_64-unknown-linux-musl` target. The `-Z unstable-options` flag must also be passed to use it on this target

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions tests/ui/linking/link-self-contained-unstable.crto.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions tests/ui/linking/link-self-contained-unstable.libc.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions tests/ui/linking/link-self-contained-unstable.mingw.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

13 changes: 13 additions & 0 deletions tests/ui/linking/link-self-contained-unstable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Checks that values for `-Clink-self-contained` other than the blanket enable/disable and
// `-linker` require `-Zunstable-options`.

//@ revisions: crto libc unwind sanitizers mingw
//@ [crto] compile-flags: -Clink-self-contained=+crto
//@ [libc] compile-flags: -Clink-self-contained=-libc
//@ [unwind] compile-flags: -Clink-self-contained=+unwind
//@ [sanitizers] compile-flags: -Clink-self-contained=-sanitizers
//@ [mingw] compile-flags: -Clink-self-contained=+mingw

fn main() {}

//~? ERROR only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

2 changes: 2 additions & 0 deletions tests/ui/linking/link-self-contained-unstable.unwind.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker` are stable, the `-Z unstable-options` flag must also be passed to use the unstable values

19 changes: 19 additions & 0 deletions tests/ui/linking/linker-features-lld-disallowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Check that only `-C linker-features=-lld` is stable on x64 linux. Any other value or target,
// needs `-Z unstable-options`.

// ignore-tidy-linelength

//@ revisions: unstable_target_positive unstable_target_negative unstable_positive
//@ [unstable_target_negative] compile-flags: --target=x86_64-unknown-linux-musl -C linker-features=-lld --crate-type=rlib
//@ [unstable_target_negative] needs-llvm-components: x86
//@ [unstable_target_positive] compile-flags: --target=x86_64-unknown-linux-musl -C linker-features=+lld --crate-type=rlib
//@ [unstable_target_positive] needs-llvm-components: x86
//@ [unstable_positive] compile-flags: --target=x86_64-unknown-linux-gnu -C linker-features=+lld --crate-type=rlib
//@ [unstable_positive] needs-llvm-components: x86


#![feature(no_core)]
#![no_core]

//[unstable_target_negative]~? ERROR `-C linker-features=-lld` is unstable on the `x86_64-unknown-linux-musl` target
//[unstable_target_positive,unstable_positive]~? ERROR `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options`
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options` flag to be used

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: `-C linker-features=-lld` is unstable on the `x86_64-unknown-linux-musl` target. The `-Z unstable-options` flag must also be passed to use it on this target

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: `-C linker-features=+lld` is unstable, and also requires the `-Z unstable-options` flag to be used

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `*lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `*lld` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `-lld@+lld` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `-lld@+lld` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

2 changes: 1 addition & 1 deletion tests/ui/linking/linker-features-malformed.no_value.stderr
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

26 changes: 13 additions & 13 deletions tests/ui/linking/linker-features-malformed.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
//! Check that malformed `-Zlinker-features` flags are properly rejected.
//! Check that malformed `-Clinker-features` flags are properly rejected.
//@ revisions: no_value
//@[no_value] compile-flags: -Zlinker-features=
//[no_value]~? ERROR incorrect value `` for unstable option `linker-features`
//@[no_value] compile-flags: -Clinker-features=
//[no_value]~? ERROR incorrect value `` for codegen option `linker-features`

//@ revisions: invalid_modifier
//@[invalid_modifier] compile-flags: -Zlinker-features=*lld
//[invalid_modifier]~? ERROR incorrect value `*lld` for unstable option `linker-features`
//@[invalid_modifier] compile-flags: -Clinker-features=*lld
//[invalid_modifier]~? ERROR incorrect value `*lld` for codegen option `linker-features`

//@ revisions: unknown_value
//@[unknown_value] compile-flags: -Zlinker-features=unknown
//[unknown_value]~? ERROR incorrect value `unknown` for unstable option `linker-features`
//@[unknown_value] compile-flags: -Clinker-features=unknown
//[unknown_value]~? ERROR incorrect value `unknown` for codegen option `linker-features`

//@ revisions: unknown_modifier_value
//@[unknown_modifier_value] compile-flags: -Zlinker-features=-unknown
//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for unstable option `linker-features`
//@[unknown_modifier_value] compile-flags: -Clinker-features=-unknown
//[unknown_modifier_value]~? ERROR incorrect value `-unknown` for codegen option `linker-features`

//@ revisions: unknown_boolean
//@[unknown_boolean] compile-flags: -Zlinker-features=maybe
//[unknown_boolean]~? ERROR incorrect value `maybe` for unstable option `linker-features`
//@[unknown_boolean] compile-flags: -Clinker-features=maybe
//[unknown_boolean]~? ERROR incorrect value `maybe` for codegen option `linker-features`

//@ revisions: invalid_separator
//@[invalid_separator] compile-flags: -Zlinker-features=-lld@+lld
//[invalid_separator]~? ERROR incorrect value `-lld@+lld` for unstable option `linker-features`
//@[invalid_separator] compile-flags: -Clinker-features=-lld@+lld
//[invalid_separator]~? ERROR incorrect value `-lld@+lld` for codegen option `linker-features`

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `maybe` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `maybe` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `-unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `-unknown` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
error: incorrect value `unknown` for unstable option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected
error: incorrect value `unknown` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected

13 changes: 13 additions & 0 deletions tests/ui/linking/linker-features-unstable-cc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Check that only `-C linker-features=-lld` is stable on x64 linux, and that other linker
// features require using `-Z unstable-options`.
//
// Note that, currently, only `lld` is parsed on the CLI, but that other linker features can exist
// internally (`cc`).
//
//@ compile-flags: --target=x86_64-unknown-linux-gnu -C linker-features=+cc --crate-type=rlib
//@ needs-llvm-components: x86

#![feature(no_core)]
#![no_core]

//~? ERROR incorrect value `+cc` for codegen option `linker-features`
2 changes: 2 additions & 0 deletions tests/ui/linking/linker-features-unstable-cc.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
error: incorrect value `+cc` for codegen option `linker-features` - a list of enabled (`+` prefix) and disabled (`-` prefix) features: `lld` was expected