Skip to content

Commit 14f651e

Browse files
committed
-Zretpoline and -Zretpoline-external-thunk flags (target modifiers) to enable retpoline-related target features
1 parent 52882f6 commit 14f651e

22 files changed

+244
-93
lines changed

compiler/rustc_codegen_gcc/messages.ftl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
55
codegen_gcc_invalid_minimum_alignment =
66
invalid minimum global alignment: {$err}
77
8-
codegen_gcc_forbidden_ctarget_feature =
9-
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
10-
118
codegen_gcc_unwinding_inline_asm =
129
GCC backend does not support unwinding from inline asm
1310
@@ -29,10 +26,6 @@ codegen_gcc_unknown_ctarget_feature =
2926
.possible_feature = you might have meant: `{$rust_feature}`
3027
.consider_filing_feature_request = consider filing a feature request
3128
32-
codegen_gcc_unstable_ctarget_feature =
33-
unstable feature specified for `-Ctarget-feature`: `{$feature}`
34-
.note = this feature is not stably supported; its behavior can change in the future
35-
3629
codegen_gcc_missing_features =
3730
add the missing features in a `target_feature` attribute
3831

compiler/rustc_codegen_gcc/src/errors.rs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
1717
pub rust_feature: PossibleFeature<'a>,
1818
}
1919

20-
#[derive(Diagnostic)]
21-
#[diag(codegen_gcc_unstable_ctarget_feature)]
22-
#[note]
23-
pub(crate) struct UnstableCTargetFeature<'a> {
24-
pub feature: &'a str,
25-
}
26-
27-
#[derive(Diagnostic)]
28-
#[diag(codegen_gcc_forbidden_ctarget_feature)]
29-
pub(crate) struct ForbiddenCTargetFeature<'a> {
30-
pub feature: &'a str,
31-
pub enabled: &'a str,
32-
pub reason: &'a str,
33-
}
34-
3520
#[derive(Subdiagnostic)]
3621
pub(crate) enum PossibleFeature<'a> {
3722
#[help(codegen_gcc_possible_feature)]

compiler/rustc_codegen_gcc/src/gcc_util.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_data_structures::unord::UnordSet;
77
use rustc_session::Session;
8+
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
89
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
910
use smallvec::{SmallVec, smallvec};
1011

11-
use crate::errors::{
12-
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
13-
UnstableCTargetFeature,
14-
};
12+
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
13+
14+
fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
15+
let mut features: Vec<&str> = Vec::new();
16+
retpoline_features_by_flags(sess, &mut features);
17+
features
18+
}
1519

1620
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
1721
/// `--target` and similar).
@@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
4549

4650
// Compute implied features
4751
let mut all_rust_features = vec![];
48-
for feature in sess.opts.cg.target_feature.split(',') {
52+
for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
4953
if let Some(feature) = feature.strip_prefix('+') {
5054
all_rust_features.extend(
5155
UnordSet::from(sess.target.implied_target_features(feature))
@@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
9498
sess.dcx().emit_warn(unknown_feature);
9599
}
96100
Some(&(_, stability, _)) => {
97-
if let Err(reason) = stability.toggle_allowed() {
98-
sess.dcx().emit_warn(ForbiddenCTargetFeature {
99-
feature,
100-
enabled: if enable { "enabled" } else { "disabled" },
101-
reason,
102-
});
103-
} else if stability.requires_nightly().is_some() {
104-
// An unstable feature. Warn about using it. (It makes little sense
105-
// to hard-error here since we just warn about fully unknown
106-
// features above).
107-
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
108-
}
101+
stability.verify_feature_enabled_by_flag(sess, enable, feature);
109102
}
110103
}
111104

compiler/rustc_codegen_llvm/messages.ftl

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
1010
1111
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
1212
13-
codegen_llvm_forbidden_ctarget_feature =
14-
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
15-
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
16-
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
17-
1813
codegen_llvm_from_llvm_diag = {$message}
1914
2015
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
@@ -82,10 +77,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
8277
8378
codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
8479
85-
codegen_llvm_unstable_ctarget_feature =
86-
unstable feature specified for `-Ctarget-feature`: `{$feature}`
87-
.note = this feature is not stably supported; its behavior can change in the future
88-
8980
codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
9081
9182
codegen_llvm_write_ir = failed to write LLVM IR to {$path}

compiler/rustc_codegen_llvm/src/errors.rs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
2424
pub rust_feature: PossibleFeature<'a>,
2525
}
2626

27-
#[derive(Diagnostic)]
28-
#[diag(codegen_llvm_unstable_ctarget_feature)]
29-
#[note]
30-
pub(crate) struct UnstableCTargetFeature<'a> {
31-
pub feature: &'a str,
32-
}
33-
34-
#[derive(Diagnostic)]
35-
#[diag(codegen_llvm_forbidden_ctarget_feature)]
36-
#[note]
37-
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
38-
pub(crate) struct ForbiddenCTargetFeature<'a> {
39-
pub feature: &'a str,
40-
pub enabled: &'a str,
41-
pub reason: &'a str,
42-
}
43-
4427
#[derive(Subdiagnostic)]
4528
pub(crate) enum PossibleFeature<'a> {
4629
#[help(codegen_llvm_possible_feature)]

compiler/rustc_codegen_llvm/src/llvm_util.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ use rustc_fs_util::path_to_c_string;
1616
use rustc_middle::bug;
1717
use rustc_session::Session;
1818
use rustc_session::config::{PrintKind, PrintRequest};
19+
use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
1920
use rustc_span::Symbol;
2021
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
2122
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
2223
use smallvec::{SmallVec, smallvec};
2324

2425
use crate::back::write::create_informational_target_machine;
2526
use crate::errors::{
26-
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
27-
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
27+
FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
2828
};
2929
use crate::llvm;
3030

@@ -699,6 +699,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
699699
handle_native(cpu_name)
700700
}
701701

702+
fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
703+
let mut features: Vec<&str> = Vec::new();
704+
retpoline_features_by_flags(sess, &mut features);
705+
features
706+
}
707+
702708
/// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
703709
/// `--target` and similar).
704710
pub(crate) fn global_llvm_features(
@@ -779,7 +785,7 @@ pub(crate) fn global_llvm_features(
779785

780786
// Compute implied features
781787
let mut all_rust_features = vec![];
782-
for feature in sess.opts.cg.target_feature.split(',') {
788+
for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
783789
if let Some(feature) = feature.strip_prefix('+') {
784790
all_rust_features.extend(
785791
UnordSet::from(sess.target.implied_target_features(feature))
@@ -832,18 +838,7 @@ pub(crate) fn global_llvm_features(
832838
sess.dcx().emit_warn(unknown_feature);
833839
}
834840
Some((_, stability, _)) => {
835-
if let Err(reason) = stability.toggle_allowed() {
836-
sess.dcx().emit_warn(ForbiddenCTargetFeature {
837-
feature,
838-
enabled: if enable { "enabled" } else { "disabled" },
839-
reason,
840-
});
841-
} else if stability.requires_nightly().is_some() {
842-
// An unstable feature. Warn about using it. It makes little sense
843-
// to hard-error here since we just warn about fully unknown
844-
// features above.
845-
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
846-
}
841+
stability.verify_feature_enabled_by_flag(sess, enable, feature);
847842
}
848843
}
849844

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
88
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
99
use rustc_middle::query::Providers;
1010
use rustc_middle::ty::TyCtxt;
11+
use rustc_session::features::StabilityExt;
1112
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
1213
use rustc_session::parse::feature_err;
1314
use rustc_span::{Span, Symbol, sym};
@@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr(
6667

6768
// Only allow target features whose feature gates have been enabled
6869
// and which are permitted to be toggled.
69-
if let Err(reason) = stability.toggle_allowed() {
70+
if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
7071
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
7172
span: item.span(),
7273
feature,

compiler/rustc_session/messages.ftl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
4040
4141
session_file_write_fail = failed to write `{$path}` due to error `{$err}`
4242
43+
session_forbidden_ctarget_feature =
44+
target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
45+
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
46+
session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
47+
4348
session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
4449
4550
session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
@@ -132,6 +137,9 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
132137
session_unleashed_feature_help_named = skipping check for `{$gate}` feature
133138
session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
134139
140+
session_unstable_ctarget_feature =
141+
unstable feature specified for `-Ctarget-feature`: `{$feature}`
142+
.note = this feature is not stably supported; its behavior can change in the future
135143
session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
136144
137145
session_unsupported_crate_type_for_target =

compiler/rustc_session/src/config.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26492649

26502650
let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
26512651

2652+
// -Zretpoline-external-thunk also requires -Zretpoline
2653+
if unstable_opts.retpoline_external_thunk {
2654+
unstable_opts.retpoline = true;
2655+
target_modifiers.insert(
2656+
OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
2657+
"true".to_string(),
2658+
);
2659+
}
2660+
26522661
let cg = cg;
26532662

26542663
let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));

compiler/rustc_session/src/errors.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,3 +501,20 @@ pub(crate) struct SoftFloatIgnored;
501501
#[note]
502502
#[note(session_soft_float_deprecated_issue)]
503503
pub(crate) struct SoftFloatDeprecated;
504+
505+
#[derive(Diagnostic)]
506+
#[diag(session_forbidden_ctarget_feature)]
507+
#[note]
508+
#[note(session_forbidden_ctarget_feature_issue)]
509+
pub(crate) struct ForbiddenCTargetFeature<'a> {
510+
pub feature: &'a str,
511+
pub enabled: &'a str,
512+
pub reason: &'a str,
513+
}
514+
515+
#[derive(Diagnostic)]
516+
#[diag(session_unstable_ctarget_feature)]
517+
#[note]
518+
pub(crate) struct UnstableCTargetFeature<'a> {
519+
pub feature: &'a str,
520+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use rustc_target::target_features::Stability;
2+
3+
use crate::Session;
4+
use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
5+
6+
pub trait StabilityExt {
7+
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
8+
/// Otherwise, some features also may only be enabled by flag (target modifier).
9+
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
10+
/// `requires_nightly`.)
11+
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
12+
13+
/// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
14+
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
15+
}
16+
17+
impl StabilityExt for Stability {
18+
fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
19+
match self {
20+
Stability::Forbidden { reason } => Err(reason),
21+
Stability::TargetModifierOnly { reason, flag } => {
22+
if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
23+
}
24+
_ => Ok(()),
25+
}
26+
}
27+
fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
28+
if let Err(reason) = self.is_toggle_permitted(sess) {
29+
sess.dcx().emit_warn(ForbiddenCTargetFeature {
30+
feature,
31+
enabled: if enable { "enabled" } else { "disabled" },
32+
reason,
33+
});
34+
} else if self.requires_nightly().is_some() {
35+
// An unstable feature. Warn about using it. It makes little sense
36+
// to hard-error here since we just warn about fully unknown
37+
// features above.
38+
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
39+
}
40+
}
41+
}
42+
43+
pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
44+
// -Zretpoline without -Zretpoline-external-thunk enables
45+
// retpoline-indirect-branches and retpoline-indirect-calls target features
46+
let unstable_opts = &sess.opts.unstable_opts;
47+
if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
48+
features.push("+retpoline-indirect-branches");
49+
features.push("+retpoline-indirect-calls");
50+
}
51+
// -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
52+
// retpoline-external-thunk, retpoline-indirect-branches and
53+
// retpoline-indirect-calls target features
54+
if unstable_opts.retpoline_external_thunk {
55+
features.push("+retpoline-external-thunk");
56+
features.push("+retpoline-indirect-branches");
57+
features.push("+retpoline-indirect-calls");
58+
}
59+
}

compiler/rustc_session/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ pub use session::*;
2929
pub mod output;
3030

3131
pub use getopts;
32+
pub mod features;
3233

3334
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
3435

compiler/rustc_session/src/options.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,14 @@ macro_rules! top_level_options {
290290
mods.sort_by(|a, b| a.opt.cmp(&b.opt));
291291
mods
292292
}
293+
294+
pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
295+
match flag {
296+
"retpoline" => self.unstable_opts.retpoline,
297+
"retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
298+
_ => false,
299+
}
300+
}
293301
}
294302
);
295303
}
@@ -2444,6 +2452,11 @@ options! {
24442452
remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
24452453
"directory into which to write optimization remarks (if not specified, they will be \
24462454
written to standard error output)"),
2455+
retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2456+
"enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"),
2457+
retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
2458+
"enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
2459+
target features (default: no)"),
24472460
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
24482461
"use a sanitizer"),
24492462
sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],

0 commit comments

Comments
 (0)