Skip to content
Closed
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1420,7 +1420,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
Expand Down
110 changes: 88 additions & 22 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,12 +367,40 @@ 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 check_linker = |components: LinkSelfContainedComponents, polarity: &str| {
let has_linker = components.is_linker_enabled();
if has_linker && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
return Err(format!(
"`-C link-self-contained={polarity}linker` is unstable on the `{target_tuple}` \
target. The `-Z unstable-options` flag must also be passed to use it on this target",
));
}
Ok(())
};
check_linker(self.enabled_components, "+")?;
check_linker(self.disabled_components, "-")?;

// Since only the linker component is stable, any other component used is unstable, and
// that's an error.
let unstable_enabled = self.enabled_components - LinkSelfContainedComponents::LINKER;
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`\
/`+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
Expand All @@ -399,7 +427,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
Expand Down Expand Up @@ -439,6 +467,44 @@ 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 check_lld = |features: LinkerFeatures, polarity: &str| {
let has_lld = features.is_lld_enabled();
if has_lld && target_tuple.tuple() != "x86_64-unknown-linux-gnu" {
return Err(format!(
"`-C linker-features={polarity}lld` is unstable on the `{target_tuple}` \
target. The `-Z unstable-options` flag must also be passed to use it on this target",
));
}
Ok(())
};
check_lld(self.enabled, "+")?;
check_lld(self.disabled, "-")?;

// Since only lld is stable, any non-lld feature used is unstable, and that's an error.
let unstable_enabled = self.enabled - LinkerFeatures::LLD;
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!(
"the requested `-C linker-features={}` are unstable, and also require the \
`-Z unstable-options` flag to be usable",
unstable_features.join(","),
));
}

Ok(())
}
}

/// Used with `-Z assert-incr-state`.
Expand Down Expand Up @@ -2595,26 +2661,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 {
Expand Down Expand Up @@ -2646,7 +2707,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
let cg = cg;

let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
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`)
Expand All @@ -2655,6 +2715,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.
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1994,6 +1994,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,
Expand Down Expand Up @@ -2284,8 +2286,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],
Expand Down
15 changes: 13 additions & 2 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,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
Expand Down Expand Up @@ -752,7 +752,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,
Expand All @@ -761,6 +761,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)
Expand Down
4 changes: 1 addition & 3 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,9 +1326,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");
}

Expand Down
20 changes: 16 additions & 4 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,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);
}
}
Expand Down Expand Up @@ -839,7 +845,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);
}
Expand Down Expand Up @@ -1015,7 +1021,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) {
Expand Down Expand Up @@ -1784,7 +1796,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;

Expand Down
18 changes: 13 additions & 5 deletions src/bootstrap/src/core/builder/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl Cargo {
// as they don't invoke rustc at all.
Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {}
_ => {
cargo.configure_linker(builder);
cargo.configure_linker(builder, mode);
}
}

Expand Down Expand Up @@ -205,7 +205,7 @@ impl Cargo {
self
}

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;

Expand Down Expand Up @@ -260,7 +260,15 @@ impl Cargo {
}
}

for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
// When determining flags for the host (build scripts/proc macros),
// we use the snapshot compiler when building `Mode::Std` tools, and
// the current compiler when building anything else.
// We need to determine the current stage here to pass proper linker args (e.g. -C vs -Z)
// to the compiler used to compile build scripts.
// 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);
}

Expand All @@ -270,10 +278,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);
}

Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,7 @@ impl<'a> Builder<'a> {
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
}

Expand Down
6 changes: 1 addition & 5 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,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
Expand All @@ -2478,10 +2477,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 config.build.triple == "x86_64-unknown-linux-gnu"
&& config.hosts == [config.build]
&& (config.channel == "dev" || config.channel == "nightly")
{
if config.build.triple == "x86_64-unknown-linux-gnu" && config.hosts == [config.build] {
let no_llvm_config = config
.target_config
.get(&config.build)
Expand Down
Loading
Loading