inline at the callsite & warn when target features mismatch

Co-authored-by: Jamie Cunliffe <Jamie.Cunliffe@arm.com>
This commit is contained in:
James Barford-Evans 2025-08-21 14:32:10 +01:00 committed by Jamie Cunliffe
parent b2dd217dd0
commit bcfc9b5073
16 changed files with 400 additions and 27 deletions

View file

@ -29,8 +29,18 @@ pub(crate) fn apply_to_callsite(callsite: &Value, idx: AttributePlace, attrs: &[
}
/// Get LLVM attribute for the provided inline heuristic.
#[inline]
fn inline_attr<'ll>(cx: &CodegenCx<'ll, '_>, inline: InlineAttr) -> Option<&'ll Attribute> {
pub(crate) fn inline_attr<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
instance: ty::Instance<'tcx>,
) -> Option<&'ll Attribute> {
// `optnone` requires `noinline`
let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
(InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
(inline, _) => inline,
};
if !cx.tcx.sess.opts.unstable_opts.inline_llvm {
// disable LLVM inlining
return Some(AttributeKind::NoInline.create_attr(cx.llcx));
@ -346,14 +356,6 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
OptimizeAttr::Speed => {}
}
// `optnone` requires `noinline`
let inline = match (codegen_fn_attrs.inline, &codegen_fn_attrs.optimize) {
(_, OptimizeAttr::DoNotOptimize) => InlineAttr::Never,
(InlineAttr::None, _) if instance.def.requires_inline(cx.tcx) => InlineAttr::Hint,
(inline, _) => inline,
};
to_add.extend(inline_attr(cx, inline));
if cx.sess().must_emit_unwind_tables() {
to_add.push(uwtable_attr(cx.llcx, cx.sess().opts.unstable_opts.use_sync_unwind));
}
@ -488,6 +490,14 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
let function_features =
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
// Apply function attributes as per usual if there are no user defined
// target features otherwise this will get applied at the callsite.
if function_features.is_empty() {
if let Some(inline_attr) = inline_attr(cx, instance) {
to_add.push(inline_attr);
}
}
let function_features = function_features
.iter()
// Convert to LLVMFeatures and filter out unavailable ones
@ -517,6 +527,7 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
let function_features = function_features.iter().map(|s| s.as_str());
let target_features: String =
global_features.chain(function_features).intersperse(",").collect();
if !target_features.is_empty() {
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "target-features", &target_features));
}

View file

@ -1392,7 +1392,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn call(
&mut self,
llty: &'ll Type,
fn_attrs: Option<&CodegenFnAttrs>,
fn_call_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: &'ll Value,
args: &[&'ll Value],
@ -1409,10 +1409,10 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
}
// Emit CFI pointer type membership test
self.cfi_type_test(fn_attrs, fn_abi, instance, llfn);
self.cfi_type_test(fn_call_attrs, fn_abi, instance, llfn);
// Emit KCFI operand bundle
let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn);
let kcfi_bundle = self.kcfi_operand_bundle(fn_call_attrs, fn_abi, instance, llfn);
if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.as_ref()) {
bundles.push(kcfi_bundle);
}
@ -1429,6 +1429,29 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
c"".as_ptr(),
)
};
if let Some(instance) = instance {
// Attributes on the function definition being called
let fn_defn_attrs = self.cx.tcx.codegen_fn_attrs(instance.def_id());
if let Some(fn_call_attrs) = fn_call_attrs
&& !fn_call_attrs.target_features.is_empty()
// If there is an inline attribute and a target feature that matches
// we will add the attribute to the callsite otherwise we'll omit
// this and not add the attribute to prevent soundness issues.
&& let Some(inlining_rule) = attributes::inline_attr(&self.cx, instance)
&& self.cx.tcx.is_target_feature_call_safe(
&fn_call_attrs.target_features,
&fn_defn_attrs.target_features,
)
{
attributes::apply_to_callsite(
call,
llvm::AttributePlace::Function,
&[inlining_rule],
);
}
}
if let Some(fn_abi) = fn_abi {
fn_abi.apply_attrs_callsite(self, call);
}

View file

@ -428,9 +428,16 @@ fn check_result(
// llvm/llvm-project#70563).
if !codegen_fn_attrs.target_features.is_empty()
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
&& !tcx.features().target_feature_inline_always()
&& let Some(span) = interesting_spans.inline
{
tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
feature_err(
tcx.sess,
sym::target_feature_inline_always,
span,
"cannot use `#[inline(always)]` with `#[target_feature]`",
)
.emit();
}
// warn that inline has no effect when no_sanitize is present

View file

@ -645,6 +645,8 @@ declare_features! (
(unstable, super_let, "1.88.0", Some(139076)),
/// Allows subtrait items to shadow supertrait items.
(unstable, supertrait_item_shadowing, "1.86.0", Some(89151)),
/// Allows the use of target_feature when a function is marked inline(always).
(unstable, target_feature_inline_always, "CURRENT_RUSTC_VERSION", Some(145574)),
/// Allows using `#[thread_local]` on `static` items.
(unstable, thread_local, "1.0.0", Some(29594)),
/// Allows defining `trait X = A + B;` alias items.

View file

@ -5138,3 +5138,57 @@ declare_lint! {
"detects tail calls of functions marked with `#[track_caller]`",
@feature_gate = explicit_tail_calls;
}
declare_lint! {
/// The `inline_always_mismatching_target_features` lint will trigger when a
/// function with the `#[inline(always)]` and `#[target_feature(enable = "...")]`
/// attributes is called and cannot be inlined due to missing target features in the caller.
///
/// ### Example
///
/// ```rust,ignore (fails on x86_64)
/// #[inline(always)]
/// #[target_feature(enable = "fp16")]
/// unsafe fn callee() {
/// // operations using fp16 types
/// }
///
/// // Caller does not enable the required target feature
/// fn caller() {
/// unsafe { callee(); }
/// }
///
/// fn main() {
/// caller();
/// }
/// ```
///
/// This will produce:
///
/// ```text
/// warning: call to `#[inline(always)]`-annotated `callee` requires the same target features. Function will not have `alwaysinline` attribute applied
/// --> $DIR/builtin.rs:5192:14
/// |
/// 10 | unsafe { callee(); }
/// | ^^^^^^^^
/// |
/// note: `fp16` target feature enabled in `callee` here but missing from `caller`
/// --> $DIR/builtin.rs:5185:1
/// |
/// 3 | #[target_feature(enable = "fp16")]
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// 4 | unsafe fn callee() {
/// | ------------------
/// = note: `#[warn(inline_always_mismatching_target_features)]` on by default
/// warning: 1 warning emitted
/// ```
///
/// ### Explanation
///
/// Inlining a function with a target feature attribute into a caller that
/// lacks the corresponding target feature can lead to unsound behavior.
/// LLVM may select the wrong instructions or registers, or reorder
/// operations, potentially resulting in runtime errors.
pub INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
Warn,
r#"detects when a function annotated with `#[inline(always)]` and `#[target_feature(enable = "..")]` is inlined into a caller without the required target feature"#,
}

View file

@ -82,7 +82,7 @@ pub enum TargetFeatureKind {
Forced,
}
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)]
pub struct TargetFeature {
/// The name of the target feature (e.g. "avx")
pub name: Symbol,

View file

@ -0,0 +1,88 @@
use rustc_hir::attrs::InlineAttr;
use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
use rustc_middle::mir::{Body, TerminatorKind};
use rustc_middle::ty::{self, TyCtxt};
use crate::pass_manager::MirLint;
pub(super) struct CheckInlineAlwaysTargetFeature;
impl<'tcx> MirLint<'tcx> for CheckInlineAlwaysTargetFeature {
fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
check_inline_always_target_features(tcx, body)
}
}
/// `#[target_feature]`-annotated functions can be marked `#[inline]` and will only be inlined if
/// the target features match (as well as all of the other inlining heuristics). `#[inline(always)]`
/// will always inline regardless of matching target features, which can result in errors from LLVM.
/// However, it is desirable to be able to always annotate certain functions (e.g. SIMD intrinsics)
/// as `#[inline(always)]` but check the target features match in Rust to avoid the LLVM errors.
///
/// We check the caller and callee target features to ensure that this can
/// be done or emit a lint.
#[inline]
fn check_inline_always_target_features<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
let caller_def_id = body.source.def_id().expect_local();
if !tcx.def_kind(caller_def_id).has_codegen_attrs() {
return;
}
let caller_codegen_fn_attrs = tcx.codegen_fn_attrs(caller_def_id);
for bb in body.basic_blocks.iter() {
let terminator = bb.terminator();
match &terminator.kind {
TerminatorKind::Call { func, .. } | TerminatorKind::TailCall { func, .. } => {
let fn_ty = func.ty(body, tcx);
let ty::FnDef(callee_def_id, _) = *fn_ty.kind() else {
continue;
};
if !tcx.def_kind(callee_def_id).has_codegen_attrs() {
continue;
}
let callee_codegen_fn_attrs = tcx.codegen_fn_attrs(callee_def_id);
if callee_codegen_fn_attrs.inline != InlineAttr::Always
|| callee_codegen_fn_attrs.target_features.is_empty()
{
continue;
}
// Scan the users defined target features and ensure they
// match the caller.
if tcx.is_target_feature_call_safe(
&callee_codegen_fn_attrs.target_features,
&caller_codegen_fn_attrs
.target_features
.iter()
.cloned()
.chain(tcx.sess.target_features.iter().map(|feat| TargetFeature {
name: *feat,
kind: TargetFeatureKind::Implied,
}))
.collect::<Vec<_>>(),
) {
continue;
}
let callee_only: Vec<_> = callee_codegen_fn_attrs
.target_features
.iter()
.filter(|it| !caller_codegen_fn_attrs.target_features.contains(it))
.filter(|it| !matches!(it.kind, TargetFeatureKind::Implied))
.map(|it| it.name.as_str())
.collect();
crate::errors::emit_inline_always_target_feature_diagnostic(
tcx,
terminator.source_info.span,
callee_def_id,
caller_def_id.into(),
&callee_only,
);
}
_ => (),
}
}
}

View file

@ -2,6 +2,7 @@ use rustc_errors::codes::*;
use rustc_errors::{Diag, LintDiagnostic};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::AssertKind;
use rustc_middle::query::Key;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::{self, Lint};
use rustc_span::def_id::DefId;
@ -9,6 +10,46 @@ use rustc_span::{Ident, Span, Symbol};
use crate::fluent_generated as fluent;
/// Emit diagnostic for calls to `#[inline(always)]`-annotated functions with a
/// `#[target_feature]` attribute where the caller enables a different set of target features.
pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
call_span: Span,
callee_def_id: DefId,
caller_def_id: DefId,
callee_only: &[&'a str],
) {
let callee = tcx.def_path_str(callee_def_id);
let caller = tcx.def_path_str(caller_def_id);
tcx.node_span_lint(
lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES,
tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()),
call_span,
|lint| {
lint.primary_message(format!(
"call to `#[inline(always)]`-annotated `{callee}` \
requires the same target features to be inlined"
));
lint.note("function will not be inlined");
lint.note(format!(
"the following target features are on `{callee}` but missing from `{caller}`: {}",
callee_only.join(", ")
));
lint.span_note(callee_def_id.default_span(tcx), format!("`{callee}` is defined here"));
let feats = callee_only.join(",");
lint.span_suggestion(
tcx.def_span(caller_def_id).shrink_to_lo(),
format!("add `#[target_feature]` attribute to `{caller}`"),
format!("#[target_feature(enable = \"{feats}\")]\n"),
lint::Applicability::MaybeIncorrect,
);
},
);
}
#[derive(LintDiagnostic)]
#[diag(mir_transform_unconditional_recursion)]
#[help]

View file

@ -116,6 +116,7 @@ declare_passes! {
mod add_subtyping_projections : Subtyper;
mod check_inline : CheckForceInline;
mod check_call_recursion : CheckCallRecursion, CheckDropRecursion;
mod check_inline_always_target_features: CheckInlineAlwaysTargetFeature;
mod check_alignment : CheckAlignment;
mod check_enums : CheckEnums;
mod check_const_item_mutation : CheckConstItemMutation;
@ -383,6 +384,9 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
// MIR-level lints.
&Lint(check_inline::CheckForceInline),
&Lint(check_call_recursion::CheckCallRecursion),
// Check callee's target features match callers target features when
// using `#[inline(always)]`
&Lint(check_inline_always_target_features::CheckInlineAlwaysTargetFeature),
&Lint(check_packed_ref::CheckPackedRef),
&Lint(check_const_item_mutation::CheckConstItemMutation),
&Lint(function_item_references::FunctionItemReferences),

View file

@ -2154,6 +2154,7 @@ symbols! {
target_family,
target_feature,
target_feature_11,
target_feature_inline_always,
target_has_atomic,
target_has_atomic_equal_alignment,
target_has_atomic_load_store,

View file

@ -0,0 +1,9 @@
//@ only-aarch64
#[inline(always)]
//~^ ERROR cannot use `#[inline(always)]` with `#[target_feature]`
#[target_feature(enable="fp16")]
fn test() {
}
fn main() { }

View file

@ -0,0 +1,13 @@
error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]`
--> $DIR/feature-gate-target-feature-inline-always.rs:2:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
= help: add `#![feature(target_feature_inline_always)]` 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: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.

View file

@ -0,0 +1,60 @@
warning: call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined
--> $DIR/inline-always.rs:19:5
|
LL | target_feature_identity();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: function will not be inlined
= note: the following target features are on `target_feature_identity` but missing from `call_no_target_features`: neon, fp16
note: `target_feature_identity` is defined here
--> $DIR/inline-always.rs:16:1
|
LL | pub unsafe fn target_feature_identity() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `#[warn(inline_always_mismatching_target_features)]` on by default
help: add `#[target_feature]` attribute to `call_no_target_features`
|
LL + #[target_feature(enable = "neon,fp16")]
LL | unsafe fn call_no_target_features() {
|
warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined
--> $DIR/inline-always.rs:22:5
|
LL | multiple_target_features();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: function will not be inlined
= note: the following target features are on `multiple_target_features` but missing from `call_no_target_features`: fp16, sve, rdm
note: `multiple_target_features` is defined here
--> $DIR/inline-always.rs:52:1
|
LL | fn multiple_target_features() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[target_feature]` attribute to `call_no_target_features`
|
LL + #[target_feature(enable = "fp16,sve,rdm")]
LL | unsafe fn call_no_target_features() {
|
warning: call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined
--> $DIR/inline-always.rs:28:5
|
LL | multiple_target_features();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: function will not be inlined
= note: the following target features are on `multiple_target_features` but missing from `call_to_first_set`: rdm
note: `multiple_target_features` is defined here
--> $DIR/inline-always.rs:52:1
|
LL | fn multiple_target_features() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: add `#[target_feature]` attribute to `call_to_first_set`
|
LL + #[target_feature(enable = "rdm")]
LL | unsafe fn call_to_first_set() {
|
warning: 3 warnings emitted

View file

@ -0,0 +1,54 @@
//@ add-core-stubs
//@ build-pass
//@ compile-flags: --crate-type=lib
//@ revisions: aarch64
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
//@[aarch64] needs-llvm-components: aarch64
#![feature(no_core, target_feature_inline_always)]
#![no_core]
extern crate minicore;
use minicore::*;
#[inline(always)]
#[target_feature(enable = "neon,fp16")]
pub unsafe fn target_feature_identity() {}
unsafe fn call_no_target_features() {
target_feature_identity();
//~^ WARNING call to `#[inline(always)]`-annotated `target_feature_identity` requires the same target features to be inlined [inline_always_mismatching_target_features]
global_feature_enabled();
multiple_target_features();
//~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features]
}
#[target_feature(enable = "fp16,sve")]
unsafe fn call_to_first_set() {
multiple_target_features();
//~^ WARNING call to `#[inline(always)]`-annotated `multiple_target_features` requires the same target features to be inlined [inline_always_mismatching_target_features]
}
/* You can't have "fhm" without "fp16" */
#[target_feature(enable = "fhm")]
unsafe fn mismatching_features() {
target_feature_identity()
}
#[target_feature(enable = "fp16")]
unsafe fn matching_target_features() {
target_feature_identity()
}
#[inline(always)]
#[target_feature(enable = "neon")]
unsafe fn global_feature_enabled() {
}
#[inline(always)]
#[target_feature(enable = "fp16,sve")]
#[target_feature(enable="rdm")]
fn multiple_target_features() {
}

View file

@ -61,6 +61,8 @@ trait Baz {}
#[inline(always)]
//~^ ERROR: cannot use `#[inline(always)]`
//~| NOTE: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
#[target_feature(enable = "sse2")]
unsafe fn test() {}

View file

@ -106,7 +106,7 @@ LL | #[target_feature(enable = "sse2")]
= help: `#[target_feature]` can only be applied to functions
error: `#[target_feature]` attribute cannot be used on statics
--> $DIR/invalid-attribute.rs:67:1
--> $DIR/invalid-attribute.rs:69:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -114,7 +114,7 @@ LL | #[target_feature(enable = "sse2")]
= help: `#[target_feature]` can only be applied to functions
error: `#[target_feature]` attribute cannot be used on trait impl blocks
--> $DIR/invalid-attribute.rs:71:1
--> $DIR/invalid-attribute.rs:73:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -122,7 +122,7 @@ LL | #[target_feature(enable = "sse2")]
= help: `#[target_feature]` can only be applied to functions
error: `#[target_feature]` attribute cannot be used on inherent impl blocks
--> $DIR/invalid-attribute.rs:77:1
--> $DIR/invalid-attribute.rs:79:1
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -130,7 +130,7 @@ LL | #[target_feature(enable = "sse2")]
= help: `#[target_feature]` can only be applied to functions
error: `#[target_feature]` attribute cannot be used on expressions
--> $DIR/invalid-attribute.rs:98:5
--> $DIR/invalid-attribute.rs:100:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -138,18 +138,22 @@ LL | #[target_feature(enable = "sse2")]
= help: `#[target_feature]` can only be applied to functions
error: `#[target_feature]` attribute cannot be used on closures
--> $DIR/invalid-attribute.rs:104:5
--> $DIR/invalid-attribute.rs:106:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: `#[target_feature]` can be applied to methods and functions
error: cannot use `#[inline(always)]` with `#[target_feature]`
error[E0658]: cannot use `#[inline(always)]` with `#[target_feature]`
--> $DIR/invalid-attribute.rs:62:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
|
= note: see issue #145574 <https://github.com/rust-lang/rust/issues/145574> for more information
= help: add `#![feature(target_feature_inline_always)]` 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: the feature named `foo` is not valid for this target
--> $DIR/invalid-attribute.rs:20:18
@ -158,7 +162,7 @@ LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
error[E0046]: not all trait items implemented, missing: `foo`
--> $DIR/invalid-attribute.rs:73:1
--> $DIR/invalid-attribute.rs:75:1
|
LL | impl Quux for u8 {}
| ^^^^^^^^^^^^^^^^ missing `foo` in implementation
@ -167,7 +171,7 @@ LL | fn foo();
| --------- `foo` from trait
error: `#[target_feature(..)]` cannot be applied to safe trait method
--> $DIR/invalid-attribute.rs:87:5
--> $DIR/invalid-attribute.rs:89:5
|
LL | #[target_feature(enable = "sse2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
@ -176,13 +180,13 @@ LL | fn foo() {}
| -------- not an `unsafe` function
error[E0053]: method `foo` has an incompatible type for trait
--> $DIR/invalid-attribute.rs:90:5
--> $DIR/invalid-attribute.rs:92:5
|
LL | fn foo() {}
| ^^^^^^^^ expected safe fn, found unsafe fn
|
note: type in trait
--> $DIR/invalid-attribute.rs:82:5
--> $DIR/invalid-attribute.rs:84:5
|
LL | fn foo();
| ^^^^^^^^^
@ -190,7 +194,7 @@ LL | fn foo();
found signature `#[target_features] fn()`
error: the feature named `+sse2` is not valid for this target
--> $DIR/invalid-attribute.rs:109:18
--> $DIR/invalid-attribute.rs:111:18
|
LL | #[target_feature(enable = "+sse2")]
| ^^^^^^^^^^^^^^^^ `+sse2` is not valid for this target
@ -199,5 +203,5 @@ LL | #[target_feature(enable = "+sse2")]
error: aborting due to 24 previous errors
Some errors have detailed explanations: E0046, E0053, E0539.
Some errors have detailed explanations: E0046, E0053, E0539, E0658.
For more information about an error, try `rustc --explain E0046`.