explicitly model that certain ABIs require/forbid certain target features
This commit is contained in:
parent
41b579660c
commit
2bf27e09be
18 changed files with 304 additions and 273 deletions
|
@ -8,7 +8,7 @@ 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_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
|
||||||
|
|
||||||
codegen_llvm_forbidden_ctarget_feature =
|
codegen_llvm_forbidden_ctarget_feature =
|
||||||
target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
|
target feature `{$feature}` cannot be {$enabled} 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!
|
.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_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
||||||
|
@ -22,8 +22,6 @@ codegen_llvm_invalid_minimum_alignment_not_power_of_two =
|
||||||
codegen_llvm_invalid_minimum_alignment_too_large =
|
codegen_llvm_invalid_minimum_alignment_too_large =
|
||||||
invalid minimum global alignment: {$align} is too large
|
invalid minimum global alignment: {$align} is too large
|
||||||
|
|
||||||
codegen_llvm_invalid_target_feature_prefix = target feature `{$feature}` must begin with a `+` or `-`"
|
|
||||||
|
|
||||||
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
|
codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
|
||||||
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
|
codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@ pub(crate) struct UnstableCTargetFeature<'a> {
|
||||||
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
|
||||||
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
pub(crate) struct ForbiddenCTargetFeature<'a> {
|
||||||
pub feature: &'a str,
|
pub feature: &'a str,
|
||||||
|
pub enabled: &'a str,
|
||||||
pub reason: &'a str,
|
pub reason: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,12 +206,6 @@ pub(crate) struct MismatchedDataLayout<'a> {
|
||||||
pub llvm_layout: &'a str,
|
pub llvm_layout: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
|
||||||
#[diag(codegen_llvm_invalid_target_feature_prefix)]
|
|
||||||
pub(crate) struct InvalidTargetFeaturePrefix<'a> {
|
|
||||||
pub feature: &'a str,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
|
#[diag(codegen_llvm_fixed_x18_invalid_arch)]
|
||||||
pub(crate) struct FixedX18InvalidArch<'a> {
|
pub(crate) struct FixedX18InvalidArch<'a> {
|
||||||
|
|
|
@ -21,8 +21,8 @@ use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATU
|
||||||
|
|
||||||
use crate::back::write::create_informational_target_machine;
|
use crate::back::write::create_informational_target_machine;
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
FixedX18InvalidArch, ForbiddenCTargetFeature, InvalidTargetFeaturePrefix, PossibleFeature,
|
FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
|
||||||
UnknownCTargetFeature, UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
|
||||||
};
|
};
|
||||||
use crate::llvm;
|
use crate::llvm;
|
||||||
|
|
||||||
|
@ -348,7 +348,16 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
||||||
{
|
{
|
||||||
if enabled {
|
if enabled {
|
||||||
// Also add all transitively implied features.
|
// Also add all transitively implied features.
|
||||||
features.extend(sess.target.implied_target_features(std::iter::once(feature)));
|
|
||||||
|
// 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.extend(
|
||||||
|
sess.target
|
||||||
|
.implied_target_features(std::iter::once(feature.as_str()))
|
||||||
|
.iter()
|
||||||
|
.map(|s| Symbol::intern(s)),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Remove transitively reverse-implied features.
|
// Remove transitively reverse-implied features.
|
||||||
|
|
||||||
|
@ -356,7 +365,11 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
|
||||||
// `features.contains` below.
|
// `features.contains` below.
|
||||||
#[allow(rustc::potential_query_instability)]
|
#[allow(rustc::potential_query_instability)]
|
||||||
features.retain(|f| {
|
features.retain(|f| {
|
||||||
if sess.target.implied_target_features(std::iter::once(*f)).contains(&feature) {
|
if sess
|
||||||
|
.target
|
||||||
|
.implied_target_features(std::iter::once(f.as_str()))
|
||||||
|
.contains(&feature.as_str())
|
||||||
|
{
|
||||||
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
// If `f` if implies `feature`, then `!feature` implies `!f`, so we have to
|
||||||
// remove `f`. (This is the standard logical contraposition principle.)
|
// remove `f`. (This is the standard logical contraposition principle.)
|
||||||
false
|
false
|
||||||
|
@ -638,7 +651,7 @@ pub(crate) fn global_llvm_features(
|
||||||
sess.target
|
sess.target
|
||||||
.features
|
.features
|
||||||
.split(',')
|
.split(',')
|
||||||
.filter(|v| !v.is_empty() && backend_feature_name(sess, v).is_some())
|
.filter(|v| !v.is_empty())
|
||||||
// Drop +v8plus feature introduced in LLVM 20.
|
// Drop +v8plus feature introduced in LLVM 20.
|
||||||
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
|
.filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0))
|
||||||
.map(String::from),
|
.map(String::from),
|
||||||
|
@ -651,44 +664,45 @@ pub(crate) fn global_llvm_features(
|
||||||
// -Ctarget-features
|
// -Ctarget-features
|
||||||
if !only_base_features {
|
if !only_base_features {
|
||||||
let known_features = sess.target.rust_target_features();
|
let known_features = sess.target.rust_target_features();
|
||||||
|
// Will only be filled when `diagnostics` is set!
|
||||||
let mut featsmap = FxHashMap::default();
|
let mut featsmap = FxHashMap::default();
|
||||||
|
|
||||||
// insert implied features
|
// Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
|
||||||
|
// are disabled.
|
||||||
|
let (abi_enable, abi_disable) = sess.target.abi_required_features();
|
||||||
|
let abi_enable_set = FxHashSet::from_iter(abi_enable.iter().copied());
|
||||||
|
let abi_disable_set = FxHashSet::from_iter(abi_disable.iter().copied());
|
||||||
|
|
||||||
|
// Compute implied features
|
||||||
let mut all_rust_features = vec![];
|
let mut all_rust_features = vec![];
|
||||||
for feature in sess.opts.cg.target_feature.split(',') {
|
for feature in sess.opts.cg.target_feature.split(',') {
|
||||||
match feature.strip_prefix('+') {
|
if let Some(feature) = feature.strip_prefix('+') {
|
||||||
Some(feature) => all_rust_features.extend(
|
all_rust_features.extend(
|
||||||
UnordSet::from(
|
UnordSet::from(sess.target.implied_target_features(std::iter::once(feature)))
|
||||||
sess.target
|
|
||||||
.implied_target_features(std::iter::once(Symbol::intern(feature))),
|
|
||||||
)
|
|
||||||
.to_sorted_stable_ord()
|
.to_sorted_stable_ord()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| format!("+{}", s.as_str())),
|
.map(|&&s| (true, s)),
|
||||||
),
|
)
|
||||||
_ => all_rust_features.push(feature.to_string()),
|
} else if let Some(feature) = feature.strip_prefix('-') {
|
||||||
}
|
// FIXME: Why do we not remove implied features on "-" here?
|
||||||
}
|
// We do the equivalent above in `target_features_cfg`.
|
||||||
|
// See <https://github.com/rust-lang/rust/issues/134792>.
|
||||||
let feats = all_rust_features
|
all_rust_features.push((false, feature));
|
||||||
.iter()
|
} else if !feature.is_empty() {
|
||||||
.filter_map(|s| {
|
|
||||||
let enable_disable = match s.chars().next() {
|
|
||||||
None => return None,
|
|
||||||
Some(c @ ('+' | '-')) => c,
|
|
||||||
Some(_) => {
|
|
||||||
if diagnostics {
|
if diagnostics {
|
||||||
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature: s });
|
sess.dcx().emit_warn(UnknownCTargetFeaturePrefix { feature });
|
||||||
}
|
}
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
// Remove features that are meant for rustc, not LLVM.
|
||||||
|
all_rust_features.retain(|(_, feature)| {
|
||||||
|
// Retain if it is not a rustc feature
|
||||||
|
!RUSTC_SPECIFIC_FEATURES.contains(feature)
|
||||||
|
});
|
||||||
|
|
||||||
// Get the backend feature name, if any.
|
// Check feature validity.
|
||||||
// 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 {
|
if diagnostics {
|
||||||
|
for &(enable, feature) in &all_rust_features {
|
||||||
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
let feature_state = known_features.iter().find(|&&(v, _, _)| v == feature);
|
||||||
match feature_state {
|
match feature_state {
|
||||||
None => {
|
None => {
|
||||||
|
@ -709,18 +723,17 @@ pub(crate) fn global_llvm_features(
|
||||||
rust_feature: PossibleFeature::Some { rust_feature },
|
rust_feature: PossibleFeature::Some { rust_feature },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UnknownCTargetFeature {
|
UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
|
||||||
feature,
|
|
||||||
rust_feature: PossibleFeature::None,
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
sess.dcx().emit_warn(unknown_feature);
|
sess.dcx().emit_warn(unknown_feature);
|
||||||
}
|
}
|
||||||
Some((_, stability, _)) => {
|
Some((_, stability, _)) => {
|
||||||
if let Err(reason) =
|
if let Err(reason) = stability.toggle_allowed(&sess.target, enable) {
|
||||||
stability.toggle_allowed(&sess.target, enable_disable == '+')
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
{
|
feature,
|
||||||
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
|
enabled: if enable { "enabled" } else { "disabled" },
|
||||||
|
reason,
|
||||||
|
});
|
||||||
} else if stability.requires_nightly().is_some() {
|
} else if stability.requires_nightly().is_some() {
|
||||||
// An unstable feature. Warn about using it. It makes little sense
|
// An unstable feature. Warn about using it. It makes little sense
|
||||||
// to hard-error here since we just warn about fully unknown
|
// to hard-error here since we just warn about fully unknown
|
||||||
|
@ -730,10 +743,47 @@ pub(crate) fn global_llvm_features(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
// Ensure that the features we enable/disable are compatible with the ABI.
|
||||||
featsmap.insert(feature, enable_disable == '+');
|
if enable {
|
||||||
|
if abi_disable_set.contains(feature) {
|
||||||
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
|
feature,
|
||||||
|
enabled: "enabled",
|
||||||
|
reason: "this feature is incompatible with the target ABI",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if abi_enable_set.contains(feature) {
|
||||||
|
sess.dcx().emit_warn(ForbiddenCTargetFeature {
|
||||||
|
feature,
|
||||||
|
enabled: "disabled",
|
||||||
|
reason: "this feature is required by the target ABI",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME(nagisa): figure out how to not allocate a full hashset here.
|
||||||
|
featsmap.insert(feature, enable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To be sure the ABI-relevant features are all in the right state, we explicitly
|
||||||
|
// (un)set them here. This means if the target spec sets those features wrong,
|
||||||
|
// we will silently correct them rather than silently producing wrong code.
|
||||||
|
// (The target sanity check tries to catch this, but we can't know which features are
|
||||||
|
// enabled in LLVM by default so we can't be fully sure about that check.)
|
||||||
|
for feature in abi_enable {
|
||||||
|
all_rust_features.push((true, feature));
|
||||||
|
}
|
||||||
|
for feature in abi_disable {
|
||||||
|
all_rust_features.push((false, feature));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate this into LLVM features.
|
||||||
|
let feats = all_rust_features
|
||||||
|
.iter()
|
||||||
|
.filter_map(|&(enable, feature)| {
|
||||||
|
let enable_disable = if enable { '+' } else { '-' };
|
||||||
// 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
|
// passing requests down to LLVM. This means that all in-language
|
||||||
// features also work on the command line instead of having two
|
// features also work on the command line instead of having two
|
||||||
|
@ -746,9 +796,9 @@ pub(crate) fn global_llvm_features(
|
||||||
enable_disable, llvm_feature.llvm_feature_name
|
enable_disable, llvm_feature.llvm_feature_name
|
||||||
))
|
))
|
||||||
.chain(llvm_feature.dependency.into_iter().filter_map(
|
.chain(llvm_feature.dependency.into_iter().filter_map(
|
||||||
move |feat| match (enable_disable, feat) {
|
move |feat| match (enable, feat) {
|
||||||
('-' | '+', TargetFeatureFoldStrength::Both(f))
|
(_, TargetFeatureFoldStrength::Both(f))
|
||||||
| ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
|
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {
|
||||||
Some(format!("{enable_disable}{f}"))
|
Some(format!("{enable_disable}{f}"))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -780,22 +830,6 @@ pub(crate) fn global_llvm_features(
|
||||||
features
|
features
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a feature name for the given `+feature` or `-feature` string.
|
|
||||||
///
|
|
||||||
/// Only allows features that are backend specific (i.e. not [`RUSTC_SPECIFIC_FEATURES`].)
|
|
||||||
fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> {
|
|
||||||
// features must start with a `+` or `-`.
|
|
||||||
let feature = s
|
|
||||||
.strip_prefix(&['+', '-'][..])
|
|
||||||
.unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s }));
|
|
||||||
// Rustc-specific feature requests like `+crt-static` or `-crt-static`
|
|
||||||
// are not passed down to LLVM.
|
|
||||||
if s.is_empty() || RUSTC_SPECIFIC_FEATURES.contains(&feature) {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(feature)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
|
pub(crate) fn tune_cpu(sess: &Session) -> Option<&str> {
|
||||||
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
|
let name = sess.opts.unstable_opts.tune_cpu.as_ref()?;
|
||||||
Some(handle_native(name))
|
Some(handle_native(name))
|
||||||
|
|
|
@ -67,7 +67,7 @@ codegen_ssa_failed_to_write = failed to write {$path}: {$error}
|
||||||
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
|
codegen_ssa_field_associated_value_expected = associated value expected for `{$name}`
|
||||||
|
|
||||||
codegen_ssa_forbidden_target_feature_attr =
|
codegen_ssa_forbidden_target_feature_attr =
|
||||||
target feature `{$feature}` cannot be toggled with `#[target_feature]`: {$reason}
|
target feature `{$feature}` cannot be enabled with `#[target_feature]`: {$reason}
|
||||||
|
|
||||||
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
|
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub(crate) fn from_target_feature_attr(
|
||||||
.emit();
|
.emit();
|
||||||
};
|
};
|
||||||
let rust_features = tcx.features();
|
let rust_features = tcx.features();
|
||||||
let mut added_target_features = Vec::new();
|
let (_abi_enable, abi_disable) = tcx.sess.target.abi_required_features();
|
||||||
for item in list {
|
for item in list {
|
||||||
// Only `enable = ...` is accepted in the meta-item list.
|
// Only `enable = ...` is accepted in the meta-item list.
|
||||||
if !item.has_name(sym::enable) {
|
if !item.has_name(sym::enable) {
|
||||||
|
@ -47,7 +47,7 @@ pub(crate) fn from_target_feature_attr(
|
||||||
};
|
};
|
||||||
|
|
||||||
// We allow comma separation to enable multiple features.
|
// We allow comma separation to enable multiple features.
|
||||||
added_target_features.extend(value.as_str().split(',').filter_map(|feature| {
|
for feature in value.as_str().split(',') {
|
||||||
let Some(stability) = rust_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 msg = format!("the feature named `{feature}` is not valid for this target");
|
||||||
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
|
let mut err = tcx.dcx().struct_span_err(item.span(), msg);
|
||||||
|
@ -59,7 +59,7 @@ pub(crate) fn from_target_feature_attr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err.emit();
|
err.emit();
|
||||||
return None;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only allow target features whose feature gates have been enabled
|
// Only allow target features whose feature gates have been enabled
|
||||||
|
@ -80,31 +80,25 @@ pub(crate) fn from_target_feature_attr(
|
||||||
format!("the target feature `{feature}` is currently unstable"),
|
format!("the target feature `{feature}` is currently unstable"),
|
||||||
)
|
)
|
||||||
.emit();
|
.emit();
|
||||||
|
} else {
|
||||||
|
// Add this and the implied features.
|
||||||
|
let feature_sym = Symbol::intern(feature);
|
||||||
|
for &name in tcx.implied_target_features(feature_sym) {
|
||||||
|
// But ensure the ABI does not forbid enabling this.
|
||||||
|
// Here we do assume that LLVM doesn't add even more implied features
|
||||||
|
// we don't know about, at least no features that would have ABI effects!
|
||||||
|
if abi_disable.contains(&name.as_str()) {
|
||||||
|
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||||
|
span: item.span(),
|
||||||
|
feature: name.as_str(),
|
||||||
|
reason: "this feature is incompatible with the target ABI",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
target_features.push(TargetFeature { name, implied: name != feature_sym })
|
||||||
}
|
}
|
||||||
Some(Symbol::intern(feature))
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add explicit features
|
|
||||||
target_features.extend(
|
|
||||||
added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Add implied features
|
|
||||||
let mut implied_target_features = UnordSet::new();
|
|
||||||
for feature in added_target_features.iter() {
|
|
||||||
implied_target_features.extend(tcx.implied_target_features(*feature).clone());
|
|
||||||
}
|
}
|
||||||
for feature in added_target_features.iter() {
|
|
||||||
implied_target_features.remove(feature);
|
|
||||||
}
|
}
|
||||||
target_features.extend(
|
|
||||||
implied_target_features
|
|
||||||
.into_sorted_stable_ord()
|
|
||||||
.iter()
|
|
||||||
.copied()
|
|
||||||
.map(|name| TargetFeature { name, implied: true }),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the set of target features used in a function for the purposes of
|
/// Computes the set of target features used in a function for the purposes of
|
||||||
|
@ -163,9 +157,13 @@ pub(crate) fn provide(providers: &mut Providers) {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
implied_target_features: |tcx, feature| {
|
implied_target_features: |tcx, feature: Symbol| {
|
||||||
|
let feature = feature.as_str();
|
||||||
UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
|
UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature)))
|
||||||
.into_sorted_stable_ord()
|
.into_sorted_stable_ord()
|
||||||
|
.into_iter()
|
||||||
|
.map(|s| Symbol::intern(s))
|
||||||
|
.collect()
|
||||||
},
|
},
|
||||||
asm_target_features,
|
asm_target_features,
|
||||||
..*providers
|
..*providers
|
||||||
|
|
|
@ -28,6 +28,7 @@ pub struct CodegenFnAttrs {
|
||||||
pub link_ordinal: Option<u16>,
|
pub link_ordinal: Option<u16>,
|
||||||
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
/// The `#[target_feature(enable = "...")]` attribute and the enabled
|
||||||
/// features (only enabled features are supported right now).
|
/// features (only enabled features are supported right now).
|
||||||
|
/// Implied target features have already been applied.
|
||||||
pub target_features: Vec<TargetFeature>,
|
pub target_features: Vec<TargetFeature>,
|
||||||
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
||||||
pub linkage: Option<Linkage>,
|
pub linkage: Option<Linkage>,
|
||||||
|
|
|
@ -2651,10 +2651,6 @@ impl TargetOptions {
|
||||||
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
|
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
|
||||||
self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
|
self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn has_neg_feature(&self, search_feature: &str) -> bool {
|
|
||||||
self.features.split(',').any(|f| f.strip_prefix('-').is_some_and(|f| f == search_feature))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TargetOptions {
|
impl Default for TargetOptions {
|
||||||
|
@ -3201,7 +3197,8 @@ impl Target {
|
||||||
check_matches!(
|
check_matches!(
|
||||||
&*self.llvm_abiname,
|
&*self.llvm_abiname,
|
||||||
"ilp32" | "ilp32f" | "ilp32d" | "ilp32e",
|
"ilp32" | "ilp32f" | "ilp32d" | "ilp32e",
|
||||||
"invalid RISC-V ABI name"
|
"invalid RISC-V ABI name: {}",
|
||||||
|
self.llvm_abiname,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"riscv64" => {
|
"riscv64" => {
|
||||||
|
@ -3209,7 +3206,8 @@ impl Target {
|
||||||
check_matches!(
|
check_matches!(
|
||||||
&*self.llvm_abiname,
|
&*self.llvm_abiname,
|
||||||
"lp64" | "lp64f" | "lp64d" | "lp64e",
|
"lp64" | "lp64f" | "lp64d" | "lp64e",
|
||||||
"invalid RISC-V ABI name"
|
"invalid RISC-V ABI name: {}",
|
||||||
|
self.llvm_abiname,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"arm" => {
|
"arm" => {
|
||||||
|
@ -3243,6 +3241,26 @@ impl Target {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Check that we don't mis-set any of the ABI-relevant features.
|
||||||
|
let (abi_enable, abi_disable) = self.abi_required_features();
|
||||||
|
for feat in abi_enable {
|
||||||
|
// The feature might be enabled by default so we can't *require* it to show up.
|
||||||
|
// But it must not be *disabled*.
|
||||||
|
if features_disabled.contains(feat) {
|
||||||
|
return Err(format!(
|
||||||
|
"target feature `{feat}` is required by the ABI but gets disabled in target spec"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for feat in abi_disable {
|
||||||
|
// The feature might be disable by default so we can't *require* it to show up.
|
||||||
|
// But it must not be *enabled*.
|
||||||
|
if features_enabled.contains(feat) {
|
||||||
|
return Err(format!(
|
||||||
|
"target feature `{feat}` is incompatible with the ABI but gets enabled in target spec"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -213,22 +213,7 @@ const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
|
||||||
("dotprod", unstable(sym::arm_target_feature), &["neon"]),
|
("dotprod", unstable(sym::arm_target_feature), &["neon"]),
|
||||||
("dsp", unstable(sym::arm_target_feature), &[]),
|
("dsp", unstable(sym::arm_target_feature), &[]),
|
||||||
("fp-armv8", unstable(sym::arm_target_feature), &["vfp4"]),
|
("fp-armv8", unstable(sym::arm_target_feature), &["vfp4"]),
|
||||||
(
|
("fpregs", unstable(sym::arm_target_feature), &[]),
|
||||||
"fpregs",
|
|
||||||
Stability::Unstable {
|
|
||||||
nightly_feature: sym::arm_target_feature,
|
|
||||||
allow_toggle: |target: &Target, _enable| {
|
|
||||||
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
|
|
||||||
// `fpregs` isn't needed so changing it cannot affect the ABI.
|
|
||||||
if target.has_feature("soft-float") {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err("unsound on hard-float targets because it changes float ABI")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
("i8mm", unstable(sym::arm_target_feature), &["neon"]),
|
("i8mm", unstable(sym::arm_target_feature), &["neon"]),
|
||||||
("mclass", unstable(sym::arm_target_feature), &[]),
|
("mclass", unstable(sym::arm_target_feature), &[]),
|
||||||
("neon", unstable(sym::arm_target_feature), &["vfp3"]),
|
("neon", unstable(sym::arm_target_feature), &["vfp3"]),
|
||||||
|
@ -326,28 +311,7 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
|
||||||
// FEAT_MTE & FEAT_MTE2
|
// FEAT_MTE & FEAT_MTE2
|
||||||
("mte", STABLE, &[]),
|
("mte", STABLE, &[]),
|
||||||
// FEAT_AdvSimd & FEAT_FP
|
// FEAT_AdvSimd & FEAT_FP
|
||||||
(
|
("neon", STABLE, &[]),
|
||||||
"neon",
|
|
||||||
Stability::Stable {
|
|
||||||
allow_toggle: |target, enable| {
|
|
||||||
if target.abi == "softfloat" {
|
|
||||||
// `neon` has no ABI implications for softfloat targets, we can allow this.
|
|
||||||
Ok(())
|
|
||||||
} else if enable
|
|
||||||
&& !target.has_neg_feature("fp-armv8")
|
|
||||||
&& !target.has_neg_feature("neon")
|
|
||||||
{
|
|
||||||
// neon is enabled by default, and has not been disabled, so enabling it again
|
|
||||||
// is redundant and we can permit it. Forbidding this would be a breaking change
|
|
||||||
// since this feature is stable.
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err("unsound on hard-float targets because it changes float ABI")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
// FEAT_PAUTH (address authentication)
|
// FEAT_PAUTH (address authentication)
|
||||||
("paca", STABLE, &[]),
|
("paca", STABLE, &[]),
|
||||||
// FEAT_PAUTH (generic authentication)
|
// FEAT_PAUTH (generic authentication)
|
||||||
|
@ -532,22 +496,7 @@ const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
|
||||||
("tbm", unstable(sym::tbm_target_feature), &[]),
|
("tbm", unstable(sym::tbm_target_feature), &[]),
|
||||||
("vaes", unstable(sym::avx512_target_feature), &["avx2", "aes"]),
|
("vaes", unstable(sym::avx512_target_feature), &["avx2", "aes"]),
|
||||||
("vpclmulqdq", unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
|
("vpclmulqdq", unstable(sym::avx512_target_feature), &["avx", "pclmulqdq"]),
|
||||||
(
|
("x87", unstable(sym::x87_target_feature), &[]),
|
||||||
"x87",
|
|
||||||
Stability::Unstable {
|
|
||||||
nightly_feature: sym::x87_target_feature,
|
|
||||||
allow_toggle: |target: &Target, _enable| {
|
|
||||||
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
|
|
||||||
// `fpregs` isn't needed so changing it cannot affect the ABI.
|
|
||||||
if target.has_feature("soft-float") {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err("unsound on hard-float targets because it changes float ABI")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
("xop", unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
|
("xop", unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
|
||||||
("xsave", STABLE, &[]),
|
("xsave", STABLE, &[]),
|
||||||
("xsavec", STABLE, &["xsave"]),
|
("xsavec", STABLE, &["xsave"]),
|
||||||
|
@ -590,55 +539,8 @@ const RISCV_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
("a", STABLE, &["zaamo", "zalrsc"]),
|
("a", STABLE, &["zaamo", "zalrsc"]),
|
||||||
("c", STABLE, &[]),
|
("c", STABLE, &[]),
|
||||||
(
|
("d", unstable(sym::riscv_target_feature), &["f"]),
|
||||||
"d",
|
("e", unstable(sym::riscv_target_feature), &[]),
|
||||||
Stability::Unstable {
|
|
||||||
nightly_feature: sym::riscv_target_feature,
|
|
||||||
allow_toggle: |target, enable| match &*target.llvm_abiname {
|
|
||||||
"ilp32d" | "lp64d" if !enable => {
|
|
||||||
// The ABI requires the `d` feature, so it cannot be disabled.
|
|
||||||
Err("feature is required by ABI")
|
|
||||||
}
|
|
||||||
"ilp32e" if enable => {
|
|
||||||
// ilp32e is incompatible with features that need aligned load/stores > 32 bits,
|
|
||||||
// like `d`.
|
|
||||||
Err("feature is incompatible with ABI")
|
|
||||||
}
|
|
||||||
_ => Ok(()),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&["f"],
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"e",
|
|
||||||
Stability::Unstable {
|
|
||||||
// Given that this is a negative feature, consider this before stabilizing:
|
|
||||||
// does it really make sense to enable this feature in an individual
|
|
||||||
// function with `#[target_feature]`?
|
|
||||||
nightly_feature: sym::riscv_target_feature,
|
|
||||||
allow_toggle: |target, enable| {
|
|
||||||
match &*target.llvm_abiname {
|
|
||||||
_ if !enable => {
|
|
||||||
// Disabling this feature means we can use more registers (x16-x31).
|
|
||||||
// The "e" ABIs treat them as caller-save, so it is safe to use them only
|
|
||||||
// in some parts of a program while the rest doesn't know they even exist.
|
|
||||||
// On other ABIs, the feature is already disabled anyway.
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
"ilp32e" | "lp64e" => {
|
|
||||||
// Embedded ABIs should already have the feature anyway, it's fine to enable
|
|
||||||
// it again from an ABI perspective.
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// *Not* an embedded ABI. Enabling `e` is invalid.
|
|
||||||
Err("feature is incompatible with ABI")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
&[],
|
|
||||||
),
|
|
||||||
(
|
(
|
||||||
"f",
|
"f",
|
||||||
Stability::Unstable {
|
Stability::Unstable {
|
||||||
|
@ -904,27 +806,107 @@ impl Target {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn implied_target_features(
|
pub fn implied_target_features<'a>(
|
||||||
&self,
|
&self,
|
||||||
base_features: impl Iterator<Item = Symbol>,
|
base_features: impl Iterator<Item = &'a str>,
|
||||||
) -> FxHashSet<Symbol> {
|
) -> FxHashSet<&'a str> {
|
||||||
let implied_features = self
|
let implied_features =
|
||||||
.rust_target_features()
|
self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::<FxHashMap<_, _>>();
|
||||||
.iter()
|
|
||||||
.map(|(f, _, i)| (Symbol::intern(f), i))
|
|
||||||
.collect::<FxHashMap<_, _>>();
|
|
||||||
|
|
||||||
// implied target features have their own implied target features, so we traverse the
|
// implied target features have their own implied target features, so we traverse the
|
||||||
// map until there are no more features to add
|
// map until there are no more features to add
|
||||||
let mut features = FxHashSet::default();
|
let mut features = FxHashSet::default();
|
||||||
let mut new_features = base_features.collect::<Vec<Symbol>>();
|
let mut new_features = base_features.collect::<Vec<&str>>();
|
||||||
while let Some(new_feature) = new_features.pop() {
|
while let Some(new_feature) = new_features.pop() {
|
||||||
if features.insert(new_feature) {
|
if features.insert(new_feature) {
|
||||||
if let Some(implied_features) = implied_features.get(&new_feature) {
|
if let Some(implied_features) = implied_features.get(&new_feature) {
|
||||||
new_features.extend(implied_features.iter().copied().map(Symbol::intern))
|
new_features.extend(implied_features.iter().copied())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
features
|
features
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns two lists of features:
|
||||||
|
/// the first list contains target features that must be enabled for ABI reasons,
|
||||||
|
/// and the second list contains target feature that must be disabled for ABI reasons.
|
||||||
|
///
|
||||||
|
/// All features enabled/disabled via `-Ctarget-features` and `#[target_features]` are checked
|
||||||
|
/// against this. We also check any implied features, based on the information above. If LLVM
|
||||||
|
/// implicitly enables more implied features than we do, that could bypass this check!
|
||||||
|
pub fn abi_required_features(&self) -> (&'static [&'static str], &'static [&'static str]) {
|
||||||
|
const NOTHING: (&'static [&'static str], &'static [&'static str]) = (&[], &[]);
|
||||||
|
// Some architectures don't have a clean explicit ABI designation; instead, the ABI is
|
||||||
|
// defined by target features. When that is the case, those target features must be
|
||||||
|
// "forbidden" in the list above to ensure that there is a consistent answer to the
|
||||||
|
// questions "which ABI is used".
|
||||||
|
match &*self.arch {
|
||||||
|
"x86" | "x86_64" => {
|
||||||
|
// We support 2 ABIs, hardfloat (default) and softfloat.
|
||||||
|
if self.has_feature("soft-float") {
|
||||||
|
NOTHING
|
||||||
|
} else {
|
||||||
|
// Hardfloat ABI. x87 must be enabled.
|
||||||
|
(&["x87"], &[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"arm" => {
|
||||||
|
// We support 2 ABIs, hardfloat (default) and softfloat.
|
||||||
|
if self.has_feature("soft-float") {
|
||||||
|
NOTHING
|
||||||
|
} else {
|
||||||
|
// Hardfloat ABI. x87 must be enabled.
|
||||||
|
(&["fpregs"], &[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"aarch64" | "arm64ec" => {
|
||||||
|
match &*self.abi {
|
||||||
|
"softfloat" => {
|
||||||
|
// This is not fully correct, LLVM actually doesn't let us enforce the softfloat
|
||||||
|
// ABI properly... see <https://github.com/rust-lang/rust/issues/134375>.
|
||||||
|
// FIXME: should be forbid "neon" here? But that would be a breaking change.
|
||||||
|
NOTHING
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Everything else is assumed to use a hardfloat ABI. neon and fp-armv8 must be enabled.
|
||||||
|
// These are Rust feature names and we use "neon" to control both of them.
|
||||||
|
(&["neon"], &[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"riscv32" | "riscv64" => {
|
||||||
|
match &*self.llvm_abiname {
|
||||||
|
"ilp32d" | "lp64d" => {
|
||||||
|
// Requires d (which implies f), incompatible with e.
|
||||||
|
(&["d"], &["e"])
|
||||||
|
}
|
||||||
|
"ilp32f" | "lp64f" => {
|
||||||
|
// Requires f, incompatible with e.
|
||||||
|
(&["f"], &["e"])
|
||||||
|
}
|
||||||
|
"ilp32" | "lp64" => {
|
||||||
|
// Requires nothing, incompatible with e.
|
||||||
|
(&[], &["e"])
|
||||||
|
}
|
||||||
|
"ilp32e" => {
|
||||||
|
// ilp32e is documented to be incompatible with features that need aligned
|
||||||
|
// load/stores > 32 bits, like `d`. (One could also just generate more
|
||||||
|
// complicated code to align the stack when needed, but the RISCV
|
||||||
|
// architecture manual just explicitly rules out this combination so we
|
||||||
|
// might as well.)
|
||||||
|
// Note that the `e` feature is not required: the ABI treats the extra
|
||||||
|
// registers as caller-save, so it is safe to use them only in some parts of
|
||||||
|
// a program while the rest doesn't know they even exist.
|
||||||
|
(&[], &["d"])
|
||||||
|
}
|
||||||
|
"lp64e" => {
|
||||||
|
// As above, `e` is not required.
|
||||||
|
NOTHING
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => NOTHING,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// ignore-tidy-linelength
|
// ignore-tidy-linelength
|
||||||
//@ revisions: ENABLE_SVE DISABLE_SVE DISABLE_NEON ENABLE_NEON
|
//@ revisions: ENABLE_SVE DISABLE_SVE ENABLE_NEON
|
||||||
//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
|
//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
|
||||||
//@ needs-llvm-components: aarch64
|
//@ needs-llvm-components: aarch64
|
||||||
|
|
||||||
|
@ -11,9 +11,10 @@
|
||||||
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
|
// ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
|
||||||
|
|
||||||
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
|
//@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
|
||||||
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?))*}}" }
|
// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
|
||||||
|
|
||||||
//@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
|
// The DISABLE_NEON is disabled since neon is a required target feature for this targt, it cannot be disabled.
|
||||||
|
// it would have: compile-flags: -C target-feature=-neon -Copt-level=0
|
||||||
// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" }
|
// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" }
|
||||||
|
|
||||||
//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
|
//@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
|
warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target 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: 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>
|
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
|
//@ compile-flags: --target=riscv32e-unknown-none-elf --crate-type=lib
|
||||||
//@ needs-llvm-components: x86
|
//@ needs-llvm-components: riscv
|
||||||
#![feature(no_core, lang_items)]
|
#![feature(no_core, lang_items, riscv_target_feature)]
|
||||||
#![no_core]
|
#![no_core]
|
||||||
|
|
||||||
#[lang = "sized"]
|
#[lang = "sized"]
|
||||||
pub trait Sized {}
|
pub trait Sized {}
|
||||||
|
|
||||||
#[target_feature(enable = "x87")]
|
#[target_feature(enable = "d")]
|
||||||
//~^ERROR: cannot be toggled with
|
//~^ERROR: cannot be enabled with
|
||||||
pub unsafe fn my_fun() {}
|
pub unsafe fn my_fun() {}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
error: target feature `x87` cannot be toggled with `#[target_feature]`: unsound on hard-float targets because it changes float ABI
|
error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
|
||||||
--> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18
|
--> $DIR/forbidden-hardfloat-target-feature-attribute.rs:9:18
|
||||||
|
|
|
|
||||||
LL | #[target_feature(enable = "x87")]
|
LL | #[target_feature(enable = "d")]
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
|
warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target 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: 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>
|
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
warning: target feature `x87` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
|
warning: unstable feature specified for `-Ctarget-feature`: `x87`
|
||||||
|
|
|
||||||
|
= note: this feature is not stably supported; its behavior can change in the future
|
||||||
|
|
||||||
|
warning: target feature `x87` cannot be disabled with `-Ctarget-feature`: this feature is required by the target 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: 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>
|
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
||||||
warning: 1 warning emitted
|
warning: 2 warnings emitted
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
pub trait Sized {}
|
pub trait Sized {}
|
||||||
|
|
||||||
#[target_feature(enable = "soft-float")]
|
#[target_feature(enable = "soft-float")]
|
||||||
//~^ERROR: cannot be toggled with
|
//~^ERROR: cannot be enabled with
|
||||||
pub unsafe fn my_fun() {}
|
pub unsafe fn my_fun() {}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
error: target feature `soft-float` cannot be toggled with `#[target_feature]`: unsound because it changes float ABI
|
error: target feature `soft-float` cannot be enabled with `#[target_feature]`: unsound because it changes float ABI
|
||||||
--> $DIR/forbidden-target-feature-attribute.rs:9:18
|
--> $DIR/forbidden-target-feature-attribute.rs:9:18
|
||||||
|
|
|
|
||||||
LL | #[target_feature(enable = "soft-float")]
|
LL | #[target_feature(enable = "soft-float")]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
|
warning: target feature `soft-float` cannot be disabled 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: 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>
|
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
warning: target feature `soft-float` cannot be toggled with `-Ctarget-feature`: unsound because it changes float ABI
|
warning: target feature `soft-float` cannot be enabled 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: 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>
|
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue