mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #129884 - RalfJung:forbidden-target-features, r=workingjubilee
mark some target features as 'forbidden' so they cannot be (un)set with -Ctarget-feature The context for this is https://github.com/rust-lang/rust/issues/116344: some target features change the way floats are passed between functions. Changing those target features is unsound as code compiled for the same target may now use different ABIs. So this introduces a new concept of "forbidden" target features (on top of the existing "stable " and "unstable" categories), and makes it a hard error to (un)set such a target feature. For now, the x86 and ARM feature `soft-float` is on that list. We'll have to make some effort to collect more relevant features, and similar features from other targets, but that can happen after the basic infrastructure for this landed. (These features are being collected in https://github.com/rust-lang/rust/issues/131799.) I've made this a warning for now to give people some time to speak up if this would break something. MCP: https://github.com/rust-lang/compiler-team/issues/780
This commit is contained in:
commit
e8c698bb3b
@ -8,6 +8,9 @@ codegen_gcc_invalid_minimum_alignment =
|
||||
codegen_gcc_lto_not_supported =
|
||||
LTO is not supported. You may get a linker error.
|
||||
|
||||
codegen_gcc_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`
|
||||
|
||||
codegen_gcc_unwinding_inline_asm =
|
||||
GCC backend does not support unwinding from inline asm
|
||||
|
||||
@ -24,11 +27,15 @@ codegen_gcc_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdyl
|
||||
codegen_gcc_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$gcc_err})
|
||||
|
||||
codegen_gcc_unknown_ctarget_feature =
|
||||
unknown feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = it is still passed through to the codegen backend
|
||||
unknown and unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future
|
||||
.possible_feature = you might have meant: `{$rust_feature}`
|
||||
.consider_filing_feature_request = consider filing a feature request
|
||||
|
||||
codegen_gcc_unstable_ctarget_feature =
|
||||
unstable feature specified for `-Ctarget-feature`: `{$feature}`
|
||||
.note = this feature is not stably supported; its behavior can change in the future
|
||||
|
||||
codegen_gcc_missing_features =
|
||||
add the missing features in a `target_feature` attribute
|
||||
|
||||
|
@ -17,6 +17,19 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
||||
pub rust_feature: PossibleFeature<'a>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_unstable_ctarget_feature)]
|
||||
#[note]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_gcc_forbidden_ctarget_feature)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_gcc_possible_feature)]
|
||||
|
@ -5,10 +5,13 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::bug;
|
||||
use rustc_session::Session;
|
||||
use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
|
||||
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
|
||||
use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
|
||||
use crate::errors::{
|
||||
ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
|
||||
UnstableCTargetFeature,
|
||||
};
|
||||
|
||||
/// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
|
||||
/// `--target` and similar).
|
||||
@ -43,7 +46,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||
);
|
||||
|
||||
// -Ctarget-features
|
||||
let supported_features = sess.target.supported_target_features();
|
||||
let known_features = sess.target.rust_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
let feats = sess
|
||||
.opts
|
||||
@ -62,37 +65,49 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
|
||||
}
|
||||
};
|
||||
|
||||
// Get the backend feature name, if any.
|
||||
// This excludes rustc-specific features, that do not get passed down to GCC.
|
||||
let feature = backend_feature_name(s)?;
|
||||
// Warn against use of GCC specific feature names on the CLI.
|
||||
if diagnostics && !supported_features.iter().any(|&(v, _, _)| v == feature) {
|
||||
let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let gcc_features = to_gcc_features(sess, rust_feature);
|
||||
if gcc_features.contains(&feature) && !gcc_features.contains(&rust_feature) {
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
|
||||
if diagnostics {
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let gcc_features = to_gcc_features(sess, rust_feature);
|
||||
if gcc_features.contains(&feature)
|
||||
&& !gcc_features.contains(&rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, Stability::Stable, _)) => {}
|
||||
Some((_, Stability::Unstable(_), _)) => {
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
Some((_, Stability::Forbidden { .. }, _)) => {
|
||||
sess.dcx().emit_err(ForbiddenCTargetFeature { feature });
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// rustc-specific features do not get passed down to GCC…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
// ... otherwise though we run through `to_gcc_features` when
|
||||
// passing requests down to GCC. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
|
@ -491,8 +491,9 @@ pub fn target_features(
|
||||
) -> Vec<Symbol> {
|
||||
// TODO(antoyo): use global_gcc_features.
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
Some(feature)
|
||||
|
@ -7,6 +7,11 @@ codegen_llvm_dynamic_linking_with_lto =
|
||||
|
||||
codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||
|
||||
codegen_llvm_forbidden_ctarget_feature =
|
||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
||||
.note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
codegen_llvm_from_llvm_diag = {$message}
|
||||
|
||||
codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
|
||||
|
@ -31,6 +31,15 @@ pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_llvm_forbidden_ctarget_feature)]
|
||||
#[note]
|
||||
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub(crate) enum PossibleFeature<'a> {
|
||||
#[help(codegen_llvm_possible_feature)]
|
||||
|
@ -17,12 +17,12 @@ use rustc_session::Session;
|
||||
use rustc_session::config::{PrintKind, PrintRequest};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
|
||||
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES, Stability};
|
||||
|
||||
use crate::back::write::create_informational_target_machine;
|
||||
use crate::errors::{
|
||||
FixedX18InvalidArch, InvalidTargetFeaturePrefix, PossibleFeature, UnknownCTargetFeature,
|
||||
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature,
|
||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||
};
|
||||
use crate::llvm;
|
||||
|
||||
@ -281,19 +281,29 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to generate cfg variables and apply features
|
||||
/// Must express features in the way Rust understands them
|
||||
/// Used to generate cfg variables and apply features.
|
||||
/// Must express features in the way Rust understands them.
|
||||
///
|
||||
/// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
|
||||
pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
let mut features = vec![];
|
||||
let mut features: FxHashSet<Symbol> = Default::default();
|
||||
|
||||
// Add base features for the target
|
||||
// Add base features for the target.
|
||||
// We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
|
||||
// The reason is that if LLVM considers a feature implied but we do not, we don't want that to
|
||||
// show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of
|
||||
// the target CPU, that is still expanded to target features (with all their implied features) by
|
||||
// LLVM.
|
||||
let target_machine = create_informational_target_machine(sess, true);
|
||||
// Compute which of the known target features are enabled in the 'base' target machine.
|
||||
// We only consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
|
||||
features.extend(
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter(|(feature, _, _)| {
|
||||
// skip checking special features, as LLVM may not understands them
|
||||
// skip checking special features, as LLVM may not understand them
|
||||
if RUSTC_SPECIAL_FEATURES.contains(feature) {
|
||||
return true;
|
||||
}
|
||||
@ -324,7 +334,12 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
if enabled {
|
||||
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
|
||||
} else {
|
||||
// We don't care about the order in `features` since the only thing we use it for is the
|
||||
// `features.contains` below.
|
||||
#[allow(rustc::potential_query_instability)]
|
||||
features.retain(|f| {
|
||||
// Keep a feature if it does not imply `feature`. Or, equivalently,
|
||||
// remove the reverse-dependencies of `feature`.
|
||||
!sess.target.implied_target_features(std::iter::once(*f)).contains(&feature)
|
||||
});
|
||||
}
|
||||
@ -332,8 +347,9 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
|
||||
|
||||
// Filter enabled features based on feature gates
|
||||
sess.target
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter(|(_, gate, _)| gate.is_supported())
|
||||
.filter_map(|&(feature, gate, _)| {
|
||||
if sess.is_nightly_build() || allow_unstable || gate.is_stable() {
|
||||
Some(feature)
|
||||
@ -451,9 +467,13 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine, out: &mut Str
|
||||
let mut known_llvm_target_features = FxHashSet::<&'static str>::default();
|
||||
let mut rustc_target_features = sess
|
||||
.target
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.filter_map(|(feature, _gate, _implied)| {
|
||||
.filter_map(|(feature, gate, _implied)| {
|
||||
if !gate.is_supported() {
|
||||
// Only list (experimentally) supported features.
|
||||
return None;
|
||||
}
|
||||
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these
|
||||
// strings.
|
||||
let llvm_feature = to_llvm_features(sess, *feature)?.llvm_feature_name;
|
||||
@ -605,7 +625,7 @@ pub(crate) fn global_llvm_features(
|
||||
|
||||
// -Ctarget-features
|
||||
if !only_base_features {
|
||||
let supported_features = sess.target.supported_target_features();
|
||||
let known_features = sess.target.rust_target_features();
|
||||
let mut featsmap = FxHashMap::default();
|
||||
|
||||
// insert implied features
|
||||
@ -639,50 +659,53 @@ pub(crate) fn global_llvm_features(
|
||||
}
|
||||
};
|
||||
|
||||
// Get the backend feature name, if any.
|
||||
// This excludes rustc-specific features, which do not get passed to LLVM.
|
||||
let feature = backend_feature_name(sess, s)?;
|
||||
// Warn against use of LLVM specific feature names and unstable features on the CLI.
|
||||
if diagnostics {
|
||||
let feature_state = supported_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
if feature_state.is_none() {
|
||||
let rust_feature =
|
||||
supported_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let llvm_features = to_llvm_features(sess, rust_feature)?;
|
||||
if llvm_features.contains(feature)
|
||||
&& !llvm_features.contains(rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||
match feature_state {
|
||||
None => {
|
||||
let rust_feature =
|
||||
known_features.iter().find_map(|&(rust_feature, _, _)| {
|
||||
let llvm_features = to_llvm_features(sess, rust_feature)?;
|
||||
if llvm_features.contains(feature)
|
||||
&& !llvm_features.contains(rust_feature)
|
||||
{
|
||||
Some(rust_feature)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
});
|
||||
let unknown_feature = if let Some(rust_feature) = rust_feature {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::Some { rust_feature },
|
||||
}
|
||||
} else {
|
||||
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
} else if feature_state
|
||||
.is_some_and(|(_name, feature_gate, _implied)| !feature_gate.is_stable())
|
||||
{
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
} else {
|
||||
UnknownCTargetFeature {
|
||||
feature,
|
||||
rust_feature: PossibleFeature::None,
|
||||
}
|
||||
};
|
||||
sess.dcx().emit_warn(unknown_feature);
|
||||
}
|
||||
Some((_, Stability::Stable, _)) => {}
|
||||
Some((_, Stability::Unstable(_), _)) => {
|
||||
// An unstable feature. Warn about using it.
|
||||
sess.dcx().emit_warn(UnstableCTargetFeature { feature });
|
||||
}
|
||||
Some((_, Stability::Forbidden { reason }, _)) => {
|
||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if diagnostics {
|
||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||
featsmap.insert(feature, enable_disable == '+');
|
||||
}
|
||||
|
||||
// rustc-specific features do not get passed down to LLVM…
|
||||
if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// ... otherwise though we run through `to_llvm_features` when
|
||||
// We run through `to_llvm_features` when
|
||||
// passing requests down to LLVM. This means that all in-language
|
||||
// features also work on the command line instead of having two
|
||||
// different names when the LLVM name and the Rust name differ.
|
||||
|
@ -64,6 +64,9 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
|
||||
|
||||
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
|
||||
|
||||
codegen_ssa_forbidden_target_feature_attr =
|
||||
target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason}
|
||||
|
||||
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
|
||||
|
||||
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
|
||||
|
@ -20,8 +20,8 @@ use rustc_span::symbol::Ident;
|
||||
use rustc_span::{Span, sym};
|
||||
use rustc_target::spec::{SanitizerSet, abi};
|
||||
|
||||
use crate::errors::{self, MissingFeatures, TargetFeatureDisableOrEnable};
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature};
|
||||
use crate::errors;
|
||||
use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
|
||||
|
||||
fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
||||
use rustc_middle::mir::mono::Linkage::*;
|
||||
@ -73,7 +73,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
||||
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
|
||||
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
|
||||
|
||||
let mut inline_span = None;
|
||||
let mut link_ordinal_span = None;
|
||||
@ -281,10 +281,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
check_target_feature_trait_unsafe(tcx, did, attr.span);
|
||||
}
|
||||
}
|
||||
from_target_feature(
|
||||
from_target_feature_attr(
|
||||
tcx,
|
||||
attr,
|
||||
supported_target_features,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
}
|
||||
@ -676,10 +676,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
.next()
|
||||
.map_or_else(|| tcx.def_span(did), |a| a.span);
|
||||
tcx.dcx()
|
||||
.create_err(TargetFeatureDisableOrEnable {
|
||||
.create_err(errors::TargetFeatureDisableOrEnable {
|
||||
features,
|
||||
span: Some(span),
|
||||
missing_features: Some(MissingFeatures),
|
||||
missing_features: Some(errors::MissingFeatures),
|
||||
})
|
||||
.emit();
|
||||
}
|
||||
|
@ -1027,6 +1027,15 @@ pub(crate) struct TargetFeatureSafeTrait {
|
||||
pub def: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_forbidden_target_feature_attr)]
|
||||
pub struct ForbiddenTargetFeatureAttr<'a> {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub feature: &'a str,
|
||||
pub reason: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(codegen_ssa_failed_to_get_layout)]
|
||||
pub struct FailedToGetLayout<'tcx> {
|
||||
|
@ -11,13 +11,16 @@ use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_target::target_features::{self, Stability};
|
||||
|
||||
use crate::errors;
|
||||
|
||||
pub(crate) fn from_target_feature(
|
||||
/// Compute the enabled target features from the `#[target_feature]` function attribute.
|
||||
/// Enabled target features are added to `target_features`.
|
||||
pub(crate) fn from_target_feature_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &ast::Attribute,
|
||||
supported_target_features: &UnordMap<String, Option<Symbol>>,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
let Some(list) = attr.meta_item_list() else { return };
|
||||
@ -46,12 +49,12 @@ pub(crate) fn from_target_feature(
|
||||
|
||||
// We allow comma separation to enable multiple features.
|
||||
added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
||||
let Some(feature_gate) = supported_target_features.get(feature) else {
|
||||
let Some(stability) = rust_target_features.get(feature) else {
|
||||
let msg = format!("the feature named `{feature}` is not valid for this target");
|
||||
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
|
||||
err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
|
||||
if let Some(stripped) = feature.strip_prefix('+') {
|
||||
let valid = supported_target_features.contains_key(stripped);
|
||||
let valid = rust_target_features.contains_key(stripped);
|
||||
if valid {
|
||||
err.help("consider removing the leading `+` in the feature name");
|
||||
}
|
||||
@ -61,18 +64,31 @@ pub(crate) fn from_target_feature(
|
||||
};
|
||||
|
||||
// Only allow target features whose feature gates have been enabled.
|
||||
let allowed = match feature_gate.as_ref().copied() {
|
||||
Some(name) => rust_features.enabled(name),
|
||||
None => true,
|
||||
let allowed = match stability {
|
||||
Stability::Forbidden { .. } => false,
|
||||
Stability::Stable => true,
|
||||
Stability::Unstable(name) => rust_features.enabled(*name),
|
||||
};
|
||||
if !allowed {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
feature_gate.unwrap(),
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
match stability {
|
||||
Stability::Stable => unreachable!(),
|
||||
&Stability::Unstable(lang_feature_name) => {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
lang_feature_name,
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Stability::Forbidden { reason } => {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
reason,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(Symbol::intern(feature))
|
||||
}));
|
||||
@ -138,20 +154,20 @@ pub(crate) fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId,
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers {
|
||||
supported_target_features: |tcx, cnum| {
|
||||
rust_target_features: |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// whitelist them all
|
||||
rustc_target::target_features::all_known_features()
|
||||
.map(|(a, b)| (a.to_string(), b.as_feature_name()))
|
||||
rustc_target::target_features::all_rust_features()
|
||||
.map(|(a, b)| (a.to_string(), b))
|
||||
.collect()
|
||||
} else {
|
||||
tcx.sess
|
||||
.target
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.map(|&(a, b, _)| (a.to_string(), b.as_feature_name()))
|
||||
.map(|&(a, b, _)| (a.to_string(), b))
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
|
@ -2200,10 +2200,11 @@ rustc_queries! {
|
||||
desc { "computing autoderef types for `{}`", goal.canonical.value.value }
|
||||
}
|
||||
|
||||
query supported_target_features(_: CrateNum) -> &'tcx UnordMap<String, Option<Symbol>> {
|
||||
/// Returns the Rust target features for the current target. These are not always the same as LLVM target features!
|
||||
query rust_target_features(_: CrateNum) -> &'tcx UnordMap<String, rustc_target::target_features::Stability> {
|
||||
arena_cache
|
||||
eval_always
|
||||
desc { "looking up supported target features" }
|
||||
desc { "looking up Rust target features" }
|
||||
}
|
||||
|
||||
query implied_target_features(feature: Symbol) -> &'tcx Vec<Symbol> {
|
||||
|
@ -370,8 +370,9 @@ impl CheckCfg {
|
||||
ins!(sym::sanitizer_cfi_normalize_integers, no_values);
|
||||
|
||||
ins!(sym::target_feature, empty_values).extend(
|
||||
rustc_target::target_features::all_known_features()
|
||||
.map(|(f, _sb)| f)
|
||||
rustc_target::target_features::all_rust_features()
|
||||
.filter(|(_, s)| s.is_supported())
|
||||
.map(|(f, _s)| f)
|
||||
.chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned())
|
||||
.map(Symbol::intern),
|
||||
);
|
||||
|
@ -1,10 +1,17 @@
|
||||
//! Declares Rust's target feature names for each target.
|
||||
//! Note that these are similar to but not always identical to LLVM's feature names,
|
||||
//! and Rust adds some features that do not correspond to LLVM features at all.
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
|
||||
/// Features that control behaviour of rustc, rather than the codegen.
|
||||
/// These exist globally and are not in the target-specific lists below.
|
||||
pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"];
|
||||
|
||||
/// Features that require special handling when passing to LLVM.
|
||||
/// Features that require special handling when passing to LLVM:
|
||||
/// these are target-specific (i.e., must also be listed in the target-specific list below)
|
||||
/// but do not correspond to an LLVM target feature.
|
||||
pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
|
||||
|
||||
/// Stability information for target features.
|
||||
@ -16,26 +23,47 @@ pub enum Stability {
|
||||
/// This target feature is unstable; using it in `#[target_feature]` or `#[cfg(target_feature)]`
|
||||
/// requires enabling the given nightly feature.
|
||||
Unstable(Symbol),
|
||||
/// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set in the basic
|
||||
/// target definition. Used in particular for features that change the floating-point ABI.
|
||||
Forbidden { reason: &'static str },
|
||||
}
|
||||
use Stability::*;
|
||||
|
||||
impl Stability {
|
||||
pub fn as_feature_name(self) -> Option<Symbol> {
|
||||
impl<CTX> HashStable<CTX> for Stability {
|
||||
#[inline]
|
||||
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
|
||||
std::mem::discriminant(self).hash_stable(hcx, hasher);
|
||||
match self {
|
||||
Stable => None,
|
||||
Unstable(s) => Some(s),
|
||||
Stable => {}
|
||||
Unstable(sym) => {
|
||||
sym.hash_stable(hcx, hasher);
|
||||
}
|
||||
Forbidden { .. } => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Stability {
|
||||
pub fn is_stable(self) -> bool {
|
||||
matches!(self, Stable)
|
||||
}
|
||||
|
||||
/// Forbidden features are not supported.
|
||||
pub fn is_supported(self) -> bool {
|
||||
!matches!(self, Forbidden { .. })
|
||||
}
|
||||
}
|
||||
|
||||
// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
|
||||
// and `#[cfg(target_feature)]`. They also do not trigger any warnings when used with
|
||||
// `-Ctarget-feature`.
|
||||
//
|
||||
// Note that even unstable (and even entirely unlisted) features can be used with `-Ctarget-feature`
|
||||
// on stable. Using a feature not on the list of Rust target features only emits a warning.
|
||||
// Only `cfg(target_feature)` and `#[target_feature]` actually do any stability gating.
|
||||
// `cfg(target_feature)` for unstable features just works on nightly without any feature gate.
|
||||
// `#[target_feature]` requires a feature gate.
|
||||
//
|
||||
// When adding features to the below lists
|
||||
// check whether they're named already elsewhere in rust
|
||||
// e.g. in stdarch and whether the given name matches LLVM's
|
||||
@ -46,17 +74,27 @@ impl Stability {
|
||||
// per-function level, since we would then allow safe calls from functions with `+soft-float` to
|
||||
// functions without that feature!
|
||||
//
|
||||
// When adding a new feature, be particularly mindful of features that affect function ABIs. Those
|
||||
// need to be treated very carefully to avoid introducing unsoundness! This often affects features
|
||||
// that enable/disable hardfloat support (see https://github.com/rust-lang/rust/issues/116344 for an
|
||||
// example of this going wrong), but features enabling new SIMD registers are also a concern (see
|
||||
// https://github.com/rust-lang/rust/issues/116558 for an example of this going wrong).
|
||||
// It is important for soundness that features allowed here do *not* change the function call ABI.
|
||||
// For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
|
||||
// arguments, so enabling toggling that feature would be unsound. In fact, since `-Ctarget-feature`
|
||||
// will just allow unknown features (with a warning), we have to explicitly list features that change
|
||||
// the ABI as `Forbidden` to ensure using them causes an error. Note that this is only effective if
|
||||
// such features can never be toggled via `-Ctarget-cpu`! If that is ever a possibility, we will need
|
||||
// extra checks ensuring that the LLVM-computed target features for a CPU did not (un)set a
|
||||
// `Forbidden` feature. See https://github.com/rust-lang/rust/issues/116344 for some more context.
|
||||
// FIXME: add such "forbidden" features for non-x86 targets.
|
||||
//
|
||||
// The one exception to features that change the ABI is features that enable larger vector
|
||||
// registers. Those are permitted to be listed here. This is currently unsound (see
|
||||
// https://github.com/rust-lang/rust/issues/116558); in the future we will have to ensure that
|
||||
// functions can only use such vectors as arguments/return types if the corresponding target feature
|
||||
// is enabled.
|
||||
//
|
||||
// Stabilizing a target feature requires t-lang approval.
|
||||
|
||||
type ImpliedFeatures = &'static [&'static str];
|
||||
|
||||
const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("aclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("aes", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
@ -70,6 +108,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
("neon", Unstable(sym::arm_target_feature), &["vfp3"]),
|
||||
("rclass", Unstable(sym::arm_target_feature), &[]),
|
||||
("sha2", Unstable(sym::arm_target_feature), &["neon"]),
|
||||
("soft-float", Forbidden { reason: "unsound because it changes float ABI" }, &[]),
|
||||
// This is needed for inline assembly, but shouldn't be stabilized as-is
|
||||
// since it should be enabled per-function using #[instruction_set], not
|
||||
// #[target_feature].
|
||||
@ -87,9 +126,10 @@ const ARM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
("vfp4", Unstable(sym::arm_target_feature), &["vfp3"]),
|
||||
("virtualization", Unstable(sym::arm_target_feature), &[]),
|
||||
// tidy-alphabetical-end
|
||||
// FIXME: need to also forbid turning off `fpregs` on hardfloat targets
|
||||
];
|
||||
|
||||
const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
// FEAT_AES & FEAT_PMULL
|
||||
("aes", Stable, &["neon"]),
|
||||
@ -277,7 +317,7 @@ const AARCH64_TIED_FEATURES: &[&[&str]] = &[
|
||||
&["paca", "pacg"], // Together these represent `pauth` in LLVM
|
||||
];
|
||||
|
||||
const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("adx", Stable, &[]),
|
||||
("aes", Stable, &["sse2"]),
|
||||
@ -328,6 +368,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
("sha512", Unstable(sym::sha512_sm_x86), &["avx2"]),
|
||||
("sm3", Unstable(sym::sha512_sm_x86), &["avx"]),
|
||||
("sm4", Unstable(sym::sha512_sm_x86), &["avx2"]),
|
||||
("soft-float", Forbidden { reason: "unsound because it changes float ABI" }, &[]),
|
||||
("sse", Stable, &[]),
|
||||
("sse2", Stable, &["sse"]),
|
||||
("sse3", Stable, &["sse2"]),
|
||||
@ -344,16 +385,17 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
("xsaveopt", Stable, &["xsave"]),
|
||||
("xsaves", Stable, &["xsave"]),
|
||||
// tidy-alphabetical-end
|
||||
// FIXME: need to also forbid turning off `x87` on hardfloat targets
|
||||
];
|
||||
|
||||
const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("hvx", Unstable(sym::hexagon_target_feature), &[]),
|
||||
("hvx-length128b", Unstable(sym::hexagon_target_feature), &["hvx"]),
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("altivec", Unstable(sym::powerpc_target_feature), &[]),
|
||||
("partword-atomics", Unstable(sym::powerpc_target_feature), &[]),
|
||||
@ -367,7 +409,7 @@ const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("fp64", Unstable(sym::mips_target_feature), &[]),
|
||||
("msa", Unstable(sym::mips_target_feature), &[]),
|
||||
@ -375,7 +417,7 @@ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("a", Stable, &["zaamo", "zalrsc"]),
|
||||
("c", Stable, &[]),
|
||||
@ -415,7 +457,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const WASM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("atomics", Unstable(sym::wasm_target_feature), &[]),
|
||||
("bulk-memory", Stable, &[]),
|
||||
@ -431,10 +473,10 @@ const WASM_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const BPF_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
|
||||
const BPF_FEATURES: &[(&str, Stability, ImpliedFeatures)] =
|
||||
&[("alu32", Unstable(sym::bpf_target_feature), &[])];
|
||||
|
||||
const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("10e60", Unstable(sym::csky_target_feature), &["7e10"]),
|
||||
("2e3", Unstable(sym::csky_target_feature), &["e2"]),
|
||||
@ -481,7 +523,7 @@ const CSKY_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("d", Unstable(sym::loongarch_target_feature), &["f"]),
|
||||
("f", Unstable(sym::loongarch_target_feature), &[]),
|
||||
@ -495,7 +537,7 @@ const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
||||
const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
const IBMZ_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
// tidy-alphabetical-start
|
||||
("backchain", Unstable(sym::s390x_target_feature), &[]),
|
||||
("vector", Unstable(sym::s390x_target_feature), &[]),
|
||||
@ -506,41 +548,39 @@ const IBMZ_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
|
||||
/// primitives may be documented.
|
||||
///
|
||||
/// IMPORTANT: If you're adding another feature list above, make sure to add it to this iterator!
|
||||
pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
||||
pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
|
||||
std::iter::empty()
|
||||
.chain(ARM_ALLOWED_FEATURES.iter())
|
||||
.chain(AARCH64_ALLOWED_FEATURES.iter())
|
||||
.chain(X86_ALLOWED_FEATURES.iter())
|
||||
.chain(HEXAGON_ALLOWED_FEATURES.iter())
|
||||
.chain(POWERPC_ALLOWED_FEATURES.iter())
|
||||
.chain(MIPS_ALLOWED_FEATURES.iter())
|
||||
.chain(RISCV_ALLOWED_FEATURES.iter())
|
||||
.chain(WASM_ALLOWED_FEATURES.iter())
|
||||
.chain(BPF_ALLOWED_FEATURES.iter())
|
||||
.chain(CSKY_ALLOWED_FEATURES)
|
||||
.chain(LOONGARCH_ALLOWED_FEATURES)
|
||||
.chain(IBMZ_ALLOWED_FEATURES)
|
||||
.chain(ARM_FEATURES.iter())
|
||||
.chain(AARCH64_FEATURES.iter())
|
||||
.chain(X86_FEATURES.iter())
|
||||
.chain(HEXAGON_FEATURES.iter())
|
||||
.chain(POWERPC_FEATURES.iter())
|
||||
.chain(MIPS_FEATURES.iter())
|
||||
.chain(RISCV_FEATURES.iter())
|
||||
.chain(WASM_FEATURES.iter())
|
||||
.chain(BPF_FEATURES.iter())
|
||||
.chain(CSKY_FEATURES)
|
||||
.chain(LOONGARCH_FEATURES)
|
||||
.chain(IBMZ_FEATURES)
|
||||
.cloned()
|
||||
.map(|(f, s, _)| (f, s))
|
||||
}
|
||||
|
||||
impl super::spec::Target {
|
||||
pub fn supported_target_features(
|
||||
&self,
|
||||
) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||
pub fn rust_target_features(&self) -> &'static [(&'static str, Stability, ImpliedFeatures)] {
|
||||
match &*self.arch {
|
||||
"arm" => ARM_ALLOWED_FEATURES,
|
||||
"aarch64" | "arm64ec" => AARCH64_ALLOWED_FEATURES,
|
||||
"x86" | "x86_64" => X86_ALLOWED_FEATURES,
|
||||
"hexagon" => HEXAGON_ALLOWED_FEATURES,
|
||||
"mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_ALLOWED_FEATURES,
|
||||
"powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES,
|
||||
"riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES,
|
||||
"wasm32" | "wasm64" => WASM_ALLOWED_FEATURES,
|
||||
"bpf" => BPF_ALLOWED_FEATURES,
|
||||
"csky" => CSKY_ALLOWED_FEATURES,
|
||||
"loongarch64" => LOONGARCH_ALLOWED_FEATURES,
|
||||
"s390x" => IBMZ_ALLOWED_FEATURES,
|
||||
"arm" => ARM_FEATURES,
|
||||
"aarch64" | "arm64ec" => AARCH64_FEATURES,
|
||||
"x86" | "x86_64" => X86_FEATURES,
|
||||
"hexagon" => HEXAGON_FEATURES,
|
||||
"mips" | "mips32r6" | "mips64" | "mips64r6" => MIPS_FEATURES,
|
||||
"powerpc" | "powerpc64" => POWERPC_FEATURES,
|
||||
"riscv32" | "riscv64" => RISCV_FEATURES,
|
||||
"wasm32" | "wasm64" => WASM_FEATURES,
|
||||
"bpf" => BPF_FEATURES,
|
||||
"csky" => CSKY_FEATURES,
|
||||
"loongarch64" => LOONGARCH_FEATURES,
|
||||
"s390x" => IBMZ_FEATURES,
|
||||
_ => &[],
|
||||
}
|
||||
}
|
||||
@ -557,7 +597,7 @@ impl super::spec::Target {
|
||||
base_features: impl Iterator<Item = Symbol>,
|
||||
) -> FxHashSet<Symbol> {
|
||||
let implied_features = self
|
||||
.supported_target_features()
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.map(|(f, _, i)| (Symbol::intern(f), i))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
|
@ -0,0 +1,12 @@
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
|
||||
//@ needs-llvm-components: x86
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
#[target_feature(enable = "soft-float")]
|
||||
//~^ERROR: cannot be toggled with
|
||||
pub unsafe fn my_fun() {}
|
@ -0,0 +1,8 @@
|
||||
error: target feature `soft-float` cannot be toggled with `#[target_feature]`: unsound because it changes float ABI
|
||||
--> $DIR/forbidden-target-feature-attribute.rs:10:18
|
||||
|
|
||||
LL | #[target_feature(enable = "soft-float")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
15
tests/ui/target-feature/forbidden-target-feature-cfg.rs
Normal file
15
tests/ui/target-feature/forbidden-target-feature-cfg.rs
Normal file
@ -0,0 +1,15 @@
|
||||
//@ compile-flags: --target=x86_64-unknown-none --crate-type=lib
|
||||
//@ needs-llvm-components: x86
|
||||
//@ check-pass
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
#![allow(unexpected_cfgs)]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
||||
|
||||
// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this
|
||||
// complains about the missing macro rather than showing the error... but that's good enough.
|
||||
#[cfg(target_feature = "soft-float")]
|
||||
compile_error!("the soft-float feature should not be exposed in `cfg`");
|
@ -0,0 +1,11 @@
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
|
||||
//@ needs-llvm-components: x86
|
||||
//@ compile-flags: -Ctarget-feature=-soft-float
|
||||
// For now this is just a warning.
|
||||
//@ build-pass
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
@ -0,0 +1,7 @@
|
||||
warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
11
tests/ui/target-feature/forbidden-target-feature-flag.rs
Normal file
11
tests/ui/target-feature/forbidden-target-feature-flag.rs
Normal file
@ -0,0 +1,11 @@
|
||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
|
||||
//@ needs-llvm-components: x86
|
||||
//@ compile-flags: -Ctarget-feature=+soft-float
|
||||
// For now this is just a warning.
|
||||
//@ build-pass
|
||||
#![feature(no_core, lang_items)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
pub trait Sized {}
|
@ -0,0 +1,7 @@
|
||||
warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
|
||||
|
|
||||
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
Loading…
Reference in New Issue
Block a user