Add an experimental unsafe(force_target_feature) attribute.
This uses the feature gate for https://github.com/rust-lang/rust/issues/143352, but is described in https://github.com/rust-lang/rfcs/pull/3820 which is strongly tied to the experiment.
This commit is contained in:
@@ -1596,7 +1596,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let safety = self.lower_safety(h.safety, default_safety);
|
||||
|
||||
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
|
||||
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. })
|
||||
let safety = if find_attr!(attrs, AttributeKind::TargetFeature { was_forced: false, .. })
|
||||
&& safety.is_safe()
|
||||
&& !self.tcx.sess.target.is_like_wasm
|
||||
{
|
||||
|
||||
@@ -385,18 +385,10 @@ impl<S: Stage> AttributeParser<S> for UsedParser {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TargetFeatureParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
|
||||
fn extend<'c>(
|
||||
fn parse_tf_attribute<'c, S: Stage>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
) -> impl IntoIterator<Item = (Symbol, Span)> + 'c {
|
||||
let mut features = Vec::new();
|
||||
let ArgParser::List(list) = args else {
|
||||
cx.expected_list(cx.attr_span);
|
||||
@@ -436,6 +428,25 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||
}
|
||||
}
|
||||
features
|
||||
}
|
||||
|
||||
pub(crate) struct TargetFeatureParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
|
||||
features: items,
|
||||
attr_span: span,
|
||||
was_forced: false,
|
||||
};
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_tf_attribute(cx, args)
|
||||
}
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
@@ -449,3 +460,30 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
|
||||
Warn(Target::MacroDef),
|
||||
]);
|
||||
}
|
||||
|
||||
pub(crate) struct ForceTargetFeatureParser;
|
||||
|
||||
impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser {
|
||||
type Item = (Symbol, Span);
|
||||
const PATH: &[Symbol] = &[sym::force_target_feature];
|
||||
const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
|
||||
features: items,
|
||||
attr_span: span,
|
||||
was_forced: true,
|
||||
};
|
||||
const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
|
||||
|
||||
fn extend<'c>(
|
||||
cx: &'c mut AcceptContext<'_, '_, S>,
|
||||
args: &'c ArgParser<'_>,
|
||||
) -> impl IntoIterator<Item = Self::Item> + 'c {
|
||||
parse_tf_attribute(cx, args)
|
||||
}
|
||||
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ use crate::attributes::allow_unstable::{
|
||||
};
|
||||
use crate::attributes::body::CoroutineParser;
|
||||
use crate::attributes::codegen_attrs::{
|
||||
ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
|
||||
TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser,
|
||||
NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser,
|
||||
};
|
||||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
@@ -161,6 +161,7 @@ attribute_parsers!(
|
||||
// tidy-alphabetical-start
|
||||
Combine<AllowConstFnUnstableParser>,
|
||||
Combine<AllowInternalUnstableParser>,
|
||||
Combine<ForceTargetFeatureParser>,
|
||||
Combine<ReprParser>,
|
||||
Combine<TargetFeatureParser>,
|
||||
Combine<UnstableFeatureBoundParser>,
|
||||
|
||||
@@ -193,7 +193,7 @@ fn process_builtin_attrs(
|
||||
}
|
||||
}
|
||||
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
|
||||
AttributeKind::TargetFeature(features, attr_span) => {
|
||||
AttributeKind::TargetFeature { features, attr_span, was_forced } => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
|
||||
continue;
|
||||
@@ -201,7 +201,7 @@ fn process_builtin_attrs(
|
||||
let safe_target_features =
|
||||
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
||||
codegen_fn_attrs.safe_target_features = safe_target_features;
|
||||
if safe_target_features {
|
||||
if safe_target_features && !was_forced {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions. Prior to stabilizing
|
||||
@@ -232,6 +232,7 @@ fn process_builtin_attrs(
|
||||
tcx,
|
||||
did,
|
||||
features,
|
||||
*was_forced,
|
||||
rust_target_features,
|
||||
&mut codegen_fn_attrs.target_features,
|
||||
);
|
||||
@@ -462,7 +463,7 @@ fn check_result(
|
||||
.collect(),
|
||||
) {
|
||||
let span =
|
||||
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span)
|
||||
find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature{attr_span: span, ..} => *span)
|
||||
.unwrap_or_else(|| tcx.def_span(did));
|
||||
|
||||
tcx.dcx()
|
||||
|
||||
@@ -3,7 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet};
|
||||
use rustc_hir::attrs::InstructionSetAttr;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
@@ -22,6 +22,7 @@ pub(crate) fn from_target_feature_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
features: &[(Symbol, Span)],
|
||||
was_forced: bool,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
@@ -88,7 +89,14 @@ pub(crate) fn from_target_feature_attr(
|
||||
}
|
||||
}
|
||||
}
|
||||
target_features.push(TargetFeature { name, implied: name != feature })
|
||||
let kind = if name != feature {
|
||||
TargetFeatureKind::Implied
|
||||
} else if was_forced {
|
||||
TargetFeatureKind::Forced
|
||||
} else {
|
||||
TargetFeatureKind::Enabled
|
||||
};
|
||||
target_features.push(TargetFeature { name, kind })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,6 +744,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
||||
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
|
||||
ErrorPreceding, EncodeCrossCrate::No
|
||||
),
|
||||
gated!(
|
||||
unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
|
||||
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
|
||||
),
|
||||
gated!(
|
||||
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
|
||||
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
|
||||
|
||||
@@ -480,6 +480,8 @@ declare_features! (
|
||||
(unstable, doc_cfg_hide, "1.57.0", Some(43781)),
|
||||
/// Allows `#[doc(masked)]`.
|
||||
(unstable, doc_masked, "1.21.0", Some(44027)),
|
||||
/// Allows features to allow target_feature to better interact with traits.
|
||||
(incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)),
|
||||
/// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }`
|
||||
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
|
||||
/// Allows exhaustive pattern matching on types that contain uninhabited types.
|
||||
|
||||
@@ -524,8 +524,9 @@ pub enum AttributeKind {
|
||||
/// Represents `#[rustc_std_internal_symbol]`.
|
||||
StdInternalSymbol(Span),
|
||||
|
||||
/// Represents `#[target_feature(enable = "...")]`
|
||||
TargetFeature(ThinVec<(Symbol, Span)>, Span),
|
||||
/// Represents `#[target_feature(enable = "...")]` and
|
||||
/// `#[unsafe(force_target_feature(enable = "...")]`.
|
||||
TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool },
|
||||
|
||||
/// Represents `#[track_caller]`
|
||||
TrackCaller(Span),
|
||||
|
||||
@@ -78,7 +78,7 @@ impl AttributeKind {
|
||||
SpecializationTrait(..) => No,
|
||||
Stability { .. } => Yes,
|
||||
StdInternalSymbol(..) => No,
|
||||
TargetFeature(..) => No,
|
||||
TargetFeature { .. } => No,
|
||||
TrackCaller(..) => Yes,
|
||||
TypeConst(..) => Yes,
|
||||
UnsafeSpecializationMarker(..) => No,
|
||||
|
||||
@@ -72,13 +72,23 @@ pub struct CodegenFnAttrs {
|
||||
pub patchable_function_entry: Option<PatchableFunctionEntry>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)]
|
||||
pub enum TargetFeatureKind {
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
Implied,
|
||||
/// The feature is added by the regular `target_feature` attribute.
|
||||
Enabled,
|
||||
/// The feature is added by the unsafe `force_target_feature` attribute.
|
||||
Forced,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct TargetFeature {
|
||||
/// The name of the target feature (e.g. "avx")
|
||||
pub name: Symbol,
|
||||
/// The feature is implied by another feature, rather than explicitly added by the
|
||||
/// `#[target_feature]` attribute
|
||||
pub implied: bool,
|
||||
/// The way this feature was enabled.
|
||||
pub kind: TargetFeatureKind,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
|
||||
@@ -8,7 +8,7 @@ use rustc_errors::DiagArgValue;
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
|
||||
use rustc_middle::mir::BorrowKind;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::visit::Visitor;
|
||||
@@ -522,7 +522,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|feature| {
|
||||
!feature.implied
|
||||
feature.kind == TargetFeatureKind::Enabled
|
||||
&& !self
|
||||
.body_target_features
|
||||
.iter()
|
||||
|
||||
@@ -167,7 +167,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
|
||||
self.check_deprecated(hir_id, attr, span, target)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::TargetFeature(_, attr_span)) => {
|
||||
Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => {
|
||||
self.check_target_feature(hir_id, *attr_span, target, attrs)
|
||||
}
|
||||
Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => {
|
||||
|
||||
@@ -901,6 +901,7 @@ symbols! {
|
||||
dynamic_no_pic: "dynamic-no-pic",
|
||||
e,
|
||||
edition_panic,
|
||||
effective_target_features,
|
||||
effects,
|
||||
eh_catch_typeinfo,
|
||||
eh_personality,
|
||||
@@ -1061,6 +1062,7 @@ symbols! {
|
||||
fn_ptr_addr,
|
||||
fn_ptr_trait,
|
||||
forbid,
|
||||
force_target_feature,
|
||||
forget,
|
||||
format,
|
||||
format_args,
|
||||
|
||||
@@ -537,7 +537,7 @@ impl<T> Trait<T> for X {
|
||||
}
|
||||
}
|
||||
TypeError::TargetFeatureCast(def_id) => {
|
||||
let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span);
|
||||
let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature{attr_span: span, was_forced: false, ..} => *span);
|
||||
diag.note(
|
||||
"functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
|
||||
);
|
||||
|
||||
@@ -1087,7 +1087,8 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute>
|
||||
|
||||
// treat #[target_feature(enable = "feat")] attributes as if they were
|
||||
// #[doc(cfg(target_feature = "feat"))] attributes as well
|
||||
if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features)
|
||||
if let Some(features) =
|
||||
find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features)
|
||||
{
|
||||
for (feature, _) in features {
|
||||
cfg &= Cfg::Cfg(sym::target_feature, Some(*feature));
|
||||
|
||||
@@ -930,7 +930,7 @@ fn maybe_from_hir_attr(
|
||||
),
|
||||
AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()),
|
||||
AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()),
|
||||
AK::TargetFeature(features, _span) => Attribute::TargetFeature {
|
||||
AK::TargetFeature { features, .. } => Attribute::TargetFeature {
|
||||
enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(),
|
||||
},
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
#[allow(unused)]
|
||||
use rustc_data_structures::static_assert_size;
|
||||
use rustc_hir::attrs::InlineAttr;
|
||||
use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::{
|
||||
@@ -1076,7 +1077,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> {
|
||||
.target_features
|
||||
.iter()
|
||||
.filter(|&feature| {
|
||||
!feature.implied && !ecx.tcx.sess.target_features.contains(&feature.name)
|
||||
feature.kind != TargetFeatureKind::Implied && !ecx.tcx.sess.target_features.contains(&feature.name)
|
||||
})
|
||||
.fold(String::new(), |mut s, feature| {
|
||||
if !s.is_empty() {
|
||||
|
||||
33
tests/assembly-llvm/force-target-feature.rs
Normal file
33
tests/assembly-llvm/force-target-feature.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
//@ only-x86_64
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -C opt-level=3 -C target-feature=-avx2
|
||||
//@ ignore-sgx Tests incompatible with LVI mitigations
|
||||
|
||||
#![feature(effective_target_features)]
|
||||
|
||||
use std::arch::x86_64::{__m256i, _mm256_add_epi32, _mm256_setzero_si256};
|
||||
use std::ops::Add;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
struct AvxU32(__m256i);
|
||||
|
||||
impl Add<AvxU32> for AvxU32 {
|
||||
type Output = Self;
|
||||
|
||||
#[no_mangle]
|
||||
#[inline(never)]
|
||||
#[unsafe(force_target_feature(enable = "avx2"))]
|
||||
fn add(self, oth: AvxU32) -> AvxU32 {
|
||||
// CHECK-LABEL: add:
|
||||
// CHECK-NOT: callq
|
||||
// CHECK: vpaddd
|
||||
// CHECK: retq
|
||||
Self(_mm256_add_epi32(self.0, oth.0))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert!(is_x86_feature_detected!("avx2"));
|
||||
let v = AvxU32(unsafe { _mm256_setzero_si256() });
|
||||
v + v;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
error[E0658]: the `#[force_target_feature]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-effective-target-features.rs:13:5
|
||||
|
|
||||
LL | #[unsafe(force_target_feature(enable = "avx2"))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #143352 <https://github.com/rust-lang/rust/issues/143352> for more information
|
||||
= help: add `#![feature(effective_target_features)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: `#[target_feature(..)]` cannot be applied to safe trait method
|
||||
--> $DIR/feature-gate-effective-target-features.rs:21:5
|
||||
|
|
||||
LL | #[target_feature(enable = "avx2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
|
||||
LL |
|
||||
LL | fn foo(&self) {}
|
||||
| ------------- not an `unsafe` function
|
||||
|
||||
error[E0053]: method `foo` has an incompatible type for trait
|
||||
--> $DIR/feature-gate-effective-target-features.rs:23:5
|
||||
|
|
||||
LL | fn foo(&self) {}
|
||||
| ^^^^^^^^^^^^^ expected safe fn, found unsafe fn
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/feature-gate-effective-target-features.rs:7:5
|
||||
|
|
||||
LL | fn foo(&self);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: expected signature `fn(&Bar2)`
|
||||
found signature `#[target_features] fn(&Bar2)`
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0053, E0658.
|
||||
For more information about an error, try `rustc --explain E0053`.
|
||||
@@ -0,0 +1,35 @@
|
||||
warning: the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/feature-gate-effective-target-features.rs:3:30
|
||||
|
|
||||
LL | #![cfg_attr(feature, feature(effective_target_features))]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #143352 <https://github.com/rust-lang/rust/issues/143352> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: `#[target_feature(..)]` cannot be applied to safe trait method
|
||||
--> $DIR/feature-gate-effective-target-features.rs:21:5
|
||||
|
|
||||
LL | #[target_feature(enable = "avx2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
|
||||
LL |
|
||||
LL | fn foo(&self) {}
|
||||
| ------------- not an `unsafe` function
|
||||
|
||||
error[E0053]: method `foo` has an incompatible type for trait
|
||||
--> $DIR/feature-gate-effective-target-features.rs:23:5
|
||||
|
|
||||
LL | fn foo(&self) {}
|
||||
| ^^^^^^^^^^^^^ expected safe fn, found unsafe fn
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/feature-gate-effective-target-features.rs:7:5
|
||||
|
|
||||
LL | fn foo(&self);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: expected signature `fn(&Bar2)`
|
||||
found signature `#[target_features] fn(&Bar2)`
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0053`.
|
||||
@@ -0,0 +1,27 @@
|
||||
//@ revisions: default feature
|
||||
//@ only-x86_64
|
||||
#![cfg_attr(feature, feature(effective_target_features))]
|
||||
//[feature]~^ WARN the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
trait Foo {
|
||||
fn foo(&self);
|
||||
}
|
||||
|
||||
struct Bar;
|
||||
|
||||
impl Foo for Bar {
|
||||
#[unsafe(force_target_feature(enable = "avx2"))]
|
||||
//[default]~^ ERROR the `#[force_target_feature]` attribute is an experimental feature
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
struct Bar2;
|
||||
|
||||
impl Foo for Bar2 {
|
||||
#[target_feature(enable = "avx2")]
|
||||
//~^ ERROR `#[target_feature(..)]` cannot be applied to safe trait method
|
||||
fn foo(&self) {}
|
||||
//~^ ERROR method `foo` has an incompatible type for trait
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Reference in New Issue
Block a user