Skip to content

Commit 327c7ee

Browse files
committed
Auto merge of rust-lang#133099 - RalfJung:forbidden-hardfloat-features, r=workingjubilee
forbid toggling x87 and fpregs on hard-float targets Part of rust-lang#116344, follow-up to rust-lang#129884: The `x87` target feature on x86 and the `fpregs` target feature on ARM must not be disabled on a hardfloat target, as that would change the float ABI. However, *enabling* `fpregs` on ARM is [explicitly requested](rust-lang#130988) as it seems to be useful. Therefore, we need to refine the distinction of "forbidden" target features and "allowed" target features: all (un)stable target features can determine on a per-target basis whether they should be allowed to be toggled or not. `fpregs` then checks whether the current target has the `soft-float` feature, and if yes, `fpregs` is permitted -- otherwise, it is not. (Same for `x87` on x86). Also fixes rust-lang#132351. Since `fpregs` and `x87` can be enabled on some builds and disabled on others, it would make sense that one can query it via `cfg`. Therefore, I made them behave in `cfg` like any other unstable target feature. The first commit prepares the infrastructure, but does not change behavior. The second commit then wires up `fpregs` and `x87` with that new infrastructure. r? `@workingjubilee`
2 parents e217f94 + 60eca2c commit 327c7ee

32 files changed

+611
-409
lines changed

compiler/rustc_codegen_cranelift/src/lib.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,11 @@ impl CodegenBackend for CraneliftCodegenBackend {
175175
}
176176
}
177177

178-
fn target_features(&self, sess: &Session, _allow_unstable: bool) -> Vec<rustc_span::Symbol> {
178+
fn target_features_cfg(
179+
&self,
180+
sess: &Session,
181+
_allow_unstable: bool,
182+
) -> Vec<rustc_span::Symbol> {
179183
// FIXME return the actually used target features. this is necessary for #[cfg(target_feature)]
180184
if sess.target.arch == "x86_64" && sess.target.os != "none" {
181185
// x86_64 mandates SSE2 support

compiler/rustc_codegen_gcc/messages.ftl

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ codegen_gcc_lto_not_supported =
99
LTO is not supported. You may get a linker error.
1010
1111
codegen_gcc_forbidden_ctarget_feature =
12-
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`
12+
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
1313
1414
codegen_gcc_unwinding_inline_asm =
1515
GCC backend does not support unwinding from inline asm

compiler/rustc_codegen_gcc/src/errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
2828
#[diag(codegen_gcc_forbidden_ctarget_feature)]
2929
pub(crate) struct ForbiddenCTargetFeature<'a> {
3030
pub feature: &'a str,
31+
pub reason: &'a str,
3132
}
3233

3334
#[derive(Subdiagnostic)]

compiler/rustc_codegen_gcc/src/gcc_util.rs

+12-8
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
55
use rustc_data_structures::fx::FxHashMap;
66
use rustc_middle::bug;
77
use rustc_session::Session;
8-
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
8+
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
99
use smallvec::{SmallVec, smallvec};
1010

1111
use crate::errors::{
@@ -94,13 +94,17 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
9494
};
9595
sess.dcx().emit_warn(unknown_feature);
9696
}
97-
Some((_, Stability::Stable, _)) => {}
98-
Some((_, Stability::Unstable(_), _)) => {
99-
// An unstable feature. Warn about using it.
100-
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
101-
}
102-
Some((_, Stability::Forbidden { .. }, _)) => {
103-
sess.dcx().emit_err(ForbiddenCTargetFeature { feature });
97+
Some((_, stability, _)) => {
98+
if let Err(reason) =
99+
stability.compute_toggleability(&sess.target).allow_toggle()
100+
{
101+
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
102+
} else if stability.requires_nightly().is_some() {
103+
// An unstable feature. Warn about using it. (It makes little sense
104+
// to hard-error here since we just warn about fully unknown
105+
// features above).
106+
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
107+
}
104108
}
105109
}
106110

compiler/rustc_codegen_gcc/src/lib.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ impl CodegenBackend for GccCodegenBackend {
260260
.join(sess)
261261
}
262262

263-
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
264-
target_features(sess, allow_unstable, &self.target_info)
263+
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
264+
target_features_cfg(sess, allow_unstable, &self.target_info)
265265
}
266266
}
267267

@@ -472,7 +472,8 @@ fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
472472
}
473473
}
474474

475-
pub fn target_features(
475+
/// Returns the features that should be set in `cfg(target_feature)`.
476+
fn target_features_cfg(
476477
sess: &Session,
477478
allow_unstable: bool,
478479
target_info: &LockedTargetInfo,
@@ -481,9 +482,9 @@ pub fn target_features(
481482
sess.target
482483
.rust_target_features()
483484
.iter()
484-
.filter(|(_, gate, _)| gate.is_supported())
485+
.filter(|(_, gate, _)| gate.in_cfg())
485486
.filter_map(|&(feature, gate, _)| {
486-
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
487+
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
487488
Some(feature)
488489
} else {
489490
None

compiler/rustc_codegen_llvm/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use std::mem::ManuallyDrop;
2727
use back::owned_target_machine::OwnedTargetMachine;
2828
use back::write::{create_informational_target_machine, create_target_machine};
2929
use errors::ParseTargetMachineConfig;
30-
pub use llvm_util::target_features;
30+
pub use llvm_util::target_features_cfg;
3131
use rustc_ast::expand::allocator::AllocatorKind;
3232
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
3333
use rustc_codegen_ssa::back::write::{
@@ -330,8 +330,8 @@ impl CodegenBackend for LlvmCodegenBackend {
330330
llvm_util::print_version();
331331
}
332332

333-
fn target_features(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
334-
target_features(sess, allow_unstable)
333+
fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
334+
target_features_cfg(sess, allow_unstable)
335335
}
336336

337337
fn codegen_crate<'tcx>(

compiler/rustc_codegen_llvm/src/llvm_util.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_session::Session;
1717
use rustc_session::config::{PrintKind, PrintRequest};
1818
use rustc_span::symbol::Symbol;
1919
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
20-
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability};
20+
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
2121

2222
use crate::back::write::create_informational_target_machine;
2323
use crate::errors::{
@@ -300,7 +300,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
300300
/// Must express features in the way Rust understands them.
301301
///
302302
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
303-
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
303+
pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
304304
let mut features: FxHashSet<Symbol> = Default::default();
305305

306306
// Add base features for the target.
@@ -316,7 +316,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
316316
sess.target
317317
.rust_target_features()
318318
.iter()
319-
.filter(|(_, gate, _)| gate.is_supported())
319+
.filter(|(_, gate, _)| gate.in_cfg())
320320
.filter(|(feature, _, _)| {
321321
// skip checking special features, as LLVM may not understand them
322322
if RUSTC_SPECIAL_FEATURES.contains(feature) {
@@ -372,9 +372,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
372372
sess.target
373373
.rust_target_features()
374374
.iter()
375-
.filter(|(_, gate, _)| gate.is_supported())
375+
.filter(|(_, gate, _)| gate.in_cfg())
376376
.filter_map(|&(feature, gate, _)| {
377-
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
377+
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
378378
Some(feature)
379379
} else {
380380
None
@@ -493,7 +493,7 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine, out: &mut Str
493493
.rust_target_features()
494494
.iter()
495495
.filter_map(|(feature, gate, _implied)| {
496-
if !gate.is_supported() {
496+
if !gate.in_cfg() {
497497
// Only list (experimentally) supported features.
498498
return None;
499499
}
@@ -716,13 +716,17 @@ pub(crate) fn global_llvm_features(
716716
};
717717
sess.dcx().emit_warn(unknown_feature);
718718
}
719-
Some((_, Stability::Stable, _)) => {}
720-
Some((_, Stability::Unstable(_), _)) => {
721-
// An unstable feature. Warn about using it.
722-
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
723-
}
724-
Some((_, Stability::Forbidden { reason }, _)) => {
725-
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
719+
Some((_, stability, _)) => {
720+
if let Err(reason) =
721+
stability.compute_toggleability(&sess.target).allow_toggle()
722+
{
723+
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
724+
} else if stability.requires_nightly().is_some() {
725+
// An unstable feature. Warn about using it. It makes little sense
726+
// to hard-error here since we just warn about fully unknown
727+
// features above.
728+
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
729+
}
726730
}
727731
}
728732

compiler/rustc_codegen_ssa/src/target_features.rs

+23-30
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
1111
use rustc_session::parse::feature_err;
1212
use rustc_span::Span;
1313
use rustc_span::symbol::{Symbol, sym};
14-
use rustc_target::target_features::{self, Stability};
14+
use rustc_target::target_features;
1515

1616
use crate::errors;
1717

@@ -20,7 +20,7 @@ use crate::errors;
2020
pub(crate) fn from_target_feature_attr(
2121
tcx: TyCtxt<'_>,
2222
attr: &ast::Attribute,
23-
rust_target_features: &UnordMap<String, target_features::Stability>,
23+
rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
2424
target_features: &mut Vec<TargetFeature>,
2525
) {
2626
let Some(list) = attr.meta_item_list() else { return };
@@ -63,32 +63,24 @@ pub(crate) fn from_target_feature_attr(
6363
return None;
6464
};
6565

66-
// Only allow target features whose feature gates have been enabled.
67-
let allowed = match stability {
68-
Stability::Forbidden { .. } => false,
69-
Stability::Stable => true,
70-
Stability::Unstable(name) => rust_features.enabled(*name),
71-
};
72-
if !allowed {
73-
match stability {
74-
Stability::Stable => unreachable!(),
75-
&Stability::Unstable(lang_feature_name) => {
76-
feature_err(
77-
&tcx.sess,
78-
lang_feature_name,
79-
item.span(),
80-
format!("the target feature `{feature}` is currently unstable"),
81-
)
82-
.emit();
83-
}
84-
Stability::Forbidden { reason } => {
85-
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
86-
span: item.span(),
87-
feature,
88-
reason,
89-
});
90-
}
91-
}
66+
// Only allow target features whose feature gates have been enabled
67+
// and which are permitted to be toggled.
68+
if let Err(reason) = stability.allow_toggle() {
69+
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
70+
span: item.span(),
71+
feature,
72+
reason,
73+
});
74+
} else if let Some(nightly_feature) = stability.requires_nightly()
75+
&& !rust_features.enabled(nightly_feature)
76+
{
77+
feature_err(
78+
&tcx.sess,
79+
nightly_feature,
80+
item.span(),
81+
format!("the target feature `{feature}` is currently unstable"),
82+
)
83+
.emit();
9284
}
9385
Some(Symbol::intern(feature))
9486
}));
@@ -156,18 +148,19 @@ pub(crate) fn provide(providers: &mut Providers) {
156148
*providers = Providers {
157149
rust_target_features: |tcx, cnum| {
158150
assert_eq!(cnum, LOCAL_CRATE);
151+
let target = &tcx.sess.target;
159152
if tcx.sess.opts.actually_rustdoc {
160153
// rustdoc needs to be able to document functions that use all the features, so
161154
// whitelist them all
162155
rustc_target::target_features::all_rust_features()
163-
.map(|(a, b)| (a.to_string(), b))
156+
.map(|(a, b)| (a.to_string(), b.compute_toggleability(target)))
164157
.collect()
165158
} else {
166159
tcx.sess
167160
.target
168161
.rust_target_features()
169162
.iter()
170-
.map(|&(a, b, _)| (a.to_string(), b))
163+
.map(|&(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
171164
.collect()
172165
}
173166
},

compiler/rustc_codegen_ssa/src/traits/backend.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ pub trait CodegenBackend {
4545

4646
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
4747

48-
fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
48+
/// Returns the features that should be set in `cfg(target_features)`.
49+
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
50+
fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
4951
vec![]
5052
}
5153

compiler/rustc_feature/src/unstable.rs

+1
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ declare_features! (
342342
(unstable, sse4a_target_feature, "1.27.0", Some(44839)),
343343
(unstable, tbm_target_feature, "1.27.0", Some(44839)),
344344
(unstable, wasm_target_feature, "1.30.0", Some(44839)),
345+
(unstable, x87_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)),
345346
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!
346347
// Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
347348
// !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!!

compiler/rustc_interface/src/util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
3535
pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
3636
let tf = sym::target_feature;
3737

38-
let unstable_target_features = codegen_backend.target_features(sess, true);
38+
let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
3939
sess.unstable_target_features.extend(unstable_target_features.iter().cloned());
4040

41-
let target_features = codegen_backend.target_features(sess, false);
41+
let target_features = codegen_backend.target_features_cfg(sess, false);
4242
sess.target_features.extend(target_features.iter().cloned());
4343

4444
cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat))));

compiler/rustc_middle/src/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2233,7 +2233,7 @@ rustc_queries! {
22332233
}
22342234

22352235
/// Returns the Rust target features for the current target. These are not always the same as LLVM target features!
2236-
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::Stability> {
2236+
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::StabilityComputed> {
22372237
arena_cache
22382238
eval_always
22392239
desc { "looking up Rust target features" }

compiler/rustc_session/src/config/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ impl CheckCfg {
371371

372372
ins!(sym::target_feature, empty_values).extend(
373373
rustc_target::target_features::all_rust_features()
374-
.filter(|(_, s)| s.is_supported())
374+
.filter(|(_, s)| s.in_cfg())
375375
.map(|(f, _s)| f)
376376
.chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned())
377377
.map(Symbol::intern),

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2201,6 +2201,7 @@ symbols! {
22012201
writeln_macro,
22022202
x86_amx_intrinsics,
22032203
x87_reg,
2204+
x87_target_feature,
22042205
xer,
22052206
xmm_reg,
22062207
xop_target_feature,

compiler/rustc_target/src/spec/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -2603,6 +2603,18 @@ impl TargetOptions {
26032603
.collect();
26042604
}
26052605
}
2606+
2607+
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
2608+
self.features.split(',').any(|f| {
2609+
if let Some(f) = f.strip_prefix('+')
2610+
&& f == search_feature
2611+
{
2612+
true
2613+
} else {
2614+
false
2615+
}
2616+
})
2617+
}
26062618
}
26072619

26082620
impl Default for TargetOptions {

0 commit comments

Comments
 (0)