From 2800108fd4309b883e52669729a80fdf9c6d954e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 13 Dec 2024 12:19:46 +0000 Subject: [PATCH] Treat safe target_feature functions as unsafe by default --- compiler/rustc_ast_lowering/src/delegation.rs | 10 +++++- compiler/rustc_ast_lowering/src/item.rs | 36 ++++++++++++++----- .../rustc_codegen_gcc/src/intrinsic/mod.rs | 6 ++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 6 ++-- .../rustc_codegen_ssa/src/codegen_attrs.rs | 6 ++-- compiler/rustc_hir/src/hir.rs | 16 ++++++--- .../rustc_hir_analysis/src/check/intrinsic.rs | 6 ++-- .../src/coherence/unsafety.rs | 12 +++---- compiler/rustc_hir_analysis/src/collect.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 4 +-- compiler/rustc_hir_typeck/src/coercion.rs | 11 ++++-- compiler/rustc_metadata/src/rmeta/table.rs | 15 +++++--- compiler/rustc_middle/src/ty/context.rs | 10 ++++-- compiler/rustc_middle/src/ty/mod.rs | 1 + .../rustc_mir_build/src/check_unsafety.rs | 10 ++++-- compiler/rustc_resolve/src/def_collector.rs | 4 ++- compiler/rustc_resolve/src/late.rs | 7 ++-- .../rustc_smir/src/rustc_internal/internal.rs | 2 +- .../rustc_smir/src/rustc_smir/convert/mod.rs | 2 +- .../traits/on_unimplemented.rs | 2 +- src/librustdoc/html/render/print_item.rs | 2 +- .../clippy_lints/src/doc/missing_headers.rs | 2 +- src/tools/clippy/clippy_lints/src/doc/mod.rs | 2 +- .../clippy_utils/src/check_proc_macro.rs | 4 +-- .../fn-exception-target-features.stderr | 5 +-- .../rfc-2396-target_feature-11/fn-ptr.stderr | 8 ++--- .../rfc-2396-target_feature-11/fn-traits.rs | 6 ++-- .../fn-traits.stderr | 27 +++++++------- .../safe-calls.stderr | 12 +++++++ .../rfc-2396-target_feature-11/trait-impl.rs | 1 + .../trait-impl.stderr | 19 ++++++++-- tests/ui/target-feature/invalid-attribute.rs | 4 +++ .../target-feature/invalid-attribute.stderr | 24 ++++++++++--- 33 files changed, 197 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 70c94f4019ae2..7a5a10b7ae09d 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -189,7 +189,15 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FnSig<'hir> { let header = if let Some(local_sig_id) = sig_id.as_local() { match self.resolver.delegation_fn_sigs.get(&local_sig_id) { - Some(sig) => self.lower_fn_header(sig.header, hir::Safety::Safe), + Some(sig) => self.lower_fn_header( + sig.header, + if sig.target_feature && !matches!(sig.header.safety, Safety::Unsafe(_)) { + hir::Safety::Unsafe { target_feature: true } + } else { + hir::Safety::Safe + }, + &[], + ), None => self.generate_header_error(), } } else { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 7d6c41992eb09..31678d041a3bb 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -231,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }); let sig = hir::FnSig { decl, - header: this.lower_fn_header(*header, hir::Safety::Safe), + header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; hir::ItemKind::Fn(sig, generics, body_id) @@ -609,7 +609,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs); let item = hir::ForeignItem { owner_id, ident: self.lower_ident(i.ident), @@ -633,7 +633,11 @@ impl<'hir> LoweringContext<'_, 'hir> { }); // Unmarked safety in unsafe block defaults to unsafe. - let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe); + let header = self.lower_fn_header( + sig.header, + hir::Safety::Unsafe { target_feature: false }, + attrs, + ); hir::ForeignItemKind::Fn( hir::FnSig { header, decl, span: self.lower_span(sig.span) }, @@ -644,7 +648,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ForeignItemKind::Static(box StaticItem { ty, mutability, expr: _, safety }) => { let ty = self .lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy)); - let safety = self.lower_safety(*safety, hir::Safety::Unsafe); + let safety = + self.lower_safety(*safety, hir::Safety::Unsafe { target_feature: false }); hir::ForeignItemKind::Static(ty, *mutability, safety) } @@ -748,7 +753,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -775,6 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + attrs, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } @@ -793,6 +799,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, FnDeclKind::Trait, sig.header.coroutine_kind, + attrs, ); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } @@ -878,7 +885,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs); let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( @@ -908,6 +915,7 @@ impl<'hir> LoweringContext<'_, 'hir> { i.id, if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent }, sig.header.coroutine_kind, + attrs, ); (generics, hir::ImplItemKind::Fn(sig, body_id)) @@ -1322,8 +1330,9 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, coroutine_kind: Option, + attrs: &[Attribute], ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { - let header = self.lower_fn_header(sig.header, hir::Safety::Safe); + let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs); let itctx = ImplTraitContext::Universal; let (generics, decl) = self.lower_generics(generics, id, itctx, |this| { this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind) @@ -1335,12 +1344,23 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, h: FnHeader, default_safety: hir::Safety, + attrs: &[Attribute], ) -> hir::FnHeader { let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind { hir::IsAsync::Async(span) } else { hir::IsAsync::NotAsync }; + + let default_safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature)) + && !matches!(h.safety, Safety::Unsafe(_)) + && default_safety.is_safe() + { + hir::Safety::Unsafe { target_feature: true } + } else { + default_safety + }; + hir::FnHeader { safety: self.lower_safety(h.safety, default_safety), asyncness, @@ -1394,7 +1414,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_safety(&mut self, s: Safety, default: hir::Safety) -> hir::Safety { match s { - Safety::Unsafe(_) => hir::Safety::Unsafe, + Safety::Unsafe(_) => hir::Safety::Unsafe { target_feature: false }, Safety::Default => default, Safety::Safe(_) => hir::Safety::Safe, } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 69326f409bb3e..c97f78c5eadcb 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -1222,7 +1222,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>( iter::once(i8p), tcx.types.unit, false, - rustc_hir::Safety::Unsafe, + rustc_hir::Safety::Unsafe { target_feature: false }, Abi::Rust, )), ); @@ -1233,7 +1233,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>( [i8p, i8p].iter().cloned(), tcx.types.unit, false, - rustc_hir::Safety::Unsafe, + rustc_hir::Safety::Unsafe { target_feature: false }, Abi::Rust, )), ); @@ -1242,7 +1242,7 @@ fn get_rust_try_fn<'a, 'gcc, 'tcx>( [try_fn_ty, i8p, catch_fn_ty], tcx.types.i32, false, - rustc_hir::Safety::Unsafe, + rustc_hir::Safety::Unsafe { target_feature: false }, Abi::Rust, )); let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index c38c5d4c6442c..2cae57ec74d05 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1091,7 +1091,7 @@ fn get_rust_try_fn<'ll, 'tcx>( [i8p], tcx.types.unit, false, - hir::Safety::Unsafe, + hir::Safety::Unsafe { target_feature: false }, ExternAbi::Rust, )), ); @@ -1102,7 +1102,7 @@ fn get_rust_try_fn<'ll, 'tcx>( [i8p, i8p], tcx.types.unit, false, - hir::Safety::Unsafe, + hir::Safety::Unsafe { target_feature: false }, ExternAbi::Rust, )), ); @@ -1111,7 +1111,7 @@ fn get_rust_try_fn<'ll, 'tcx>( [try_fn_ty, i8p, catch_fn_ty], tcx.types.i32, false, - hir::Safety::Unsafe, + hir::Safety::Unsafe { target_feature: false }, ExternAbi::Rust, )); let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 658a7f00b19df..e4638d22f6ca3 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -6,7 +6,7 @@ use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{HirId, LangItem, lang_items}; +use rustc_hir::{self as hir, HirId, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -251,7 +251,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::target_feature => { if !tcx.is_closure_like(did.to_def_id()) && let Some(fn_sig) = fn_sig() - && fn_sig.skip_binder().safety().is_safe() + && matches!(fn_sig.skip_binder().safety(), hir::Safety::Unsafe { + target_feature: true + }) { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index b6cdf224fb26b..3a390ffefe221 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3390,14 +3390,21 @@ impl<'hir> Item<'hir> { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] #[derive(Encodable, Decodable, HashStable_Generic)] pub enum Safety { - Unsafe, + Unsafe { + /// Whether this is a safe target_feature function. + /// We treat those as unsafe almost everywhere, but in unsafeck, + /// which allows calling them from other target_feature functions + /// without an `unsafe` block. + target_feature: bool, + }, Safe, } impl Safety { pub fn prefix_str(self) -> &'static str { match self { - Self::Unsafe => "unsafe ", + Self::Unsafe { target_feature: false } => "unsafe ", + Self::Unsafe { target_feature: true } => "#[target_feature] ", Self::Safe => "", } } @@ -3410,7 +3417,7 @@ impl Safety { #[inline] pub fn is_safe(self) -> bool { match self { - Self::Unsafe => false, + Self::Unsafe { .. } => false, Self::Safe => true, } } @@ -3419,7 +3426,8 @@ impl Safety { impl fmt::Display for Safety { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match *self { - Self::Unsafe => "unsafe", + Self::Unsafe { target_feature: false } => "unsafe", + Self::Unsafe { target_feature: true } => "#[target_feature] safe", Self::Safe => "safe", }) } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 2e6b511412bb1..190d1096857b0 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -76,7 +76,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - tcx.fn_sig(intrinsic_id).skip_binder().safety() } else { // Old-style intrinsics are never safe - Safety::Unsafe + Safety::Unsafe { target_feature: false } }; let is_in_list = match tcx.item_name(intrinsic_id.into()) { // When adding a new intrinsic to this list, @@ -137,7 +137,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::fdiv_algebraic | sym::frem_algebraic | sym::const_eval_select => hir::Safety::Safe, - _ => hir::Safety::Unsafe, + _ => hir::Safety::Unsafe { target_feature: false }, }; if has_safe_attr != is_in_list { @@ -216,7 +216,7 @@ pub fn check_intrinsic_type( return; } }; - (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe) + (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe { target_feature: false }) } else { let safety = intrinsic_operation_unsafety(tcx, intrinsic_id); let (n_tps, n_cts, inputs, output) = match intrinsic_name { diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index 86839e4033034..99f0d709103ab 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -24,7 +24,7 @@ pub(super) fn check_item( let trait_def_safety = if is_copy { // If `Self` has unsafe fields, `Copy` is unsafe to implement. if trait_header.trait_ref.skip_binder().self_ty().has_unsafe_fields() { - rustc_hir::Safety::Unsafe + rustc_hir::Safety::Unsafe { target_feature: false } } else { rustc_hir::Safety::Safe } @@ -33,7 +33,7 @@ pub(super) fn check_item( }; match (trait_def_safety, unsafe_attr, trait_header.safety, trait_header.polarity) { - (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => { + (Safety::Safe, None, Safety::Unsafe { .. }, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( tcx.dcx(), @@ -51,7 +51,7 @@ pub(super) fn check_item( .emit()); } - (Safety::Unsafe, _, Safety::Safe, Positive | Reservation) => { + (Safety::Unsafe { .. }, _, Safety::Safe, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( tcx.dcx(), @@ -109,14 +109,14 @@ pub(super) fn check_item( .emit()); } - (_, _, Safety::Unsafe, Negative) => { + (_, _, Safety::Unsafe { .. }, Negative) => { // Reported in AST validation assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl"); Ok(()) } (_, _, Safety::Safe, Negative) - | (Safety::Unsafe, _, Safety::Unsafe, Positive | Reservation) - | (Safety::Safe, Some(_), Safety::Unsafe, Positive | Reservation) + | (Safety::Unsafe { .. }, _, Safety::Unsafe { .. }, Positive | Reservation) + | (Safety::Safe, Some(_), Safety::Unsafe { .. }, Positive | Reservation) | (Safety::Safe, None, Safety::Safe, _) => Ok(()), } } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 96d2714252af9..752a7f48b1b29 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1371,7 +1371,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn // constructors for structs with `layout_scalar_valid_range` are unsafe to call let safety = match tcx.layout_scalar_valid_range(adt_def_id) { (Bound::Unbounded, Bound::Unbounded) => hir::Safety::Safe, - _ => hir::Safety::Unsafe, + _ => hir::Safety::Unsafe { target_feature: false }, }; ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, ExternAbi::Rust)) } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index a74e36c45c6ef..b91a4fbdd5368 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -2293,8 +2293,8 @@ impl<'a> State<'a> { fn print_safety(&mut self, s: hir::Safety) { match s { - hir::Safety::Safe => {} - hir::Safety::Unsafe => self.word_nbsp("unsafe"), + hir::Safety::Unsafe { target_feature: true } | hir::Safety::Safe => {} + hir::Safety::Unsafe { target_feature: false } => self.word_nbsp("unsafe"), } } diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 7d7c9331edf00..dffad13f8ba22 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -863,7 +863,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let outer_universe = self.infcx.universe(); let result = if let ty::FnPtr(_, hdr_b) = b.kind() - && fn_ty_a.safety().is_safe() + && matches!( + fn_ty_a.safety(), + hir::Safety::Safe | hir::Safety::Unsafe { target_feature: true } + ) && hdr_b.safety.is_unsafe() { let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a); @@ -924,10 +927,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::IntrinsicCast); } - // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). + // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396), + // report a better error than a safety mismatch. + // FIXME(target_feature): do this inside `coerce_from_safe_fn` if b_hdr.safety.is_safe() - && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + && matches!(a_sig.safety(), hir::Safety::Unsafe { target_feature: true }) { return Err(TypeError::TargetFeatureCast(def_id)); } diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 28f406fbc9629..b01ecb8681d79 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -155,13 +155,17 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) - ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Unsafe { target_feature: true }, mutability: ast::Mutability::Not, nested: false } ) + ( Static { safety: hir::Safety::Unsafe { target_feature: false }, mutability: ast::Mutability::Not, nested: false } ) ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: false } ) - ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: true }, mutability: ast::Mutability::Mut, nested: false } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: false }, mutability: ast::Mutability::Mut, nested: false } ) ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: false } ) - ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: true }, mutability: ast::Mutability::Not, nested: true } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: false }, mutability: ast::Mutability::Not, nested: true } ) ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Not, nested: true } ) - ( Static { safety: hir::Safety::Unsafe, mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: true }, mutability: ast::Mutability::Mut, nested: true } ) + ( Static { safety: hir::Safety::Unsafe{ target_feature: false }, mutability: ast::Mutability::Mut, nested: true } ) ( Static { safety: hir::Safety::Safe, mutability: ast::Mutability::Mut, nested: true } ) ( Ctor(CtorOf::Struct, CtorKind::Fn) ) ( Ctor(CtorOf::Struct, CtorKind::Const) ) @@ -199,7 +203,8 @@ fixed_size_enum! { fixed_size_enum! { hir::Safety { - ( Unsafe ) + ( Unsafe { target_feature: false } ) + ( Unsafe { target_feature: true } ) ( Safe ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e382e63e2bdd2..42aaa923022b3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2521,8 +2521,14 @@ impl<'tcx> TyCtxt<'tcx> { /// that is, a `fn` type that is equivalent in every way for being /// unsafe. pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> { - assert!(sig.safety().is_safe()); - Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig })) + matches!(sig.safety(), hir::Safety::Safe | hir::Safety::Unsafe { target_feature: true }); + Ty::new_fn_ptr( + self, + sig.map_bound(|sig| ty::FnSig { + safety: hir::Safety::Unsafe { target_feature: false }, + ..sig + }), + ) } /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 70d43abe8ed01..675a5de482573 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -221,6 +221,7 @@ pub struct DelegationFnSig { pub param_count: usize, pub has_self: bool, pub c_variadic: bool, + pub target_feature: bool, } #[derive(Clone, Copy, Debug)] diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 90be690e0345f..d7f53999a88fd 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -479,7 +479,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { return; // don't visit the whole expression } ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => { - if self.thir[fun].ty.fn_sig(self.tcx).safety().is_unsafe() { + if matches!(self.thir[fun].ty.fn_sig(self.tcx).safety(), hir::Safety::Unsafe { + target_feature: false + }) { let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() { Some(*func_id) } else { @@ -1112,7 +1114,11 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { let hir_id = tcx.local_def_id_to_hir_id(def); let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| { - if fn_sig.header.safety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe } + if matches!(fn_sig.header.safety, hir::Safety::Unsafe { target_feature: false }) { + SafetyContext::UnsafeFn + } else { + SafetyContext::Safe + } }); let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features; let mut warnings = Vec::new(); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 6649284258121..8be10d3de142a 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -226,7 +226,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let def_kind = match fi.kind { ForeignItemKind::Static(box StaticItem { ty: _, mutability, expr: _, safety }) => { let safety = match safety { - ast::Safety::Unsafe(_) | ast::Safety::Default => hir::Safety::Unsafe, + ast::Safety::Unsafe(_) | ast::Safety::Default => { + hir::Safety::Unsafe { target_feature: false } + } ast::Safety::Safe(_) => hir::Safety::Safe, }; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 789d74876f722..9687408ca4da9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4959,12 +4959,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> { } impl ItemInfoCollector<'_, '_, '_> { - fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) { + fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) { let sig = DelegationFnSig { header: sig.header, param_count: sig.decl.inputs.len(), has_self: sig.decl.has_self(), c_variadic: sig.decl.c_variadic(), + target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)), }; self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); } @@ -4983,7 +4984,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { | ItemKind::Trait(box Trait { ref generics, .. }) | ItemKind::TraitAlias(ref generics, _) => { if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { - self.collect_fn_info(sig, item.id); + self.collect_fn_info(sig, item.id, &item.attrs); } let def_id = self.r.local_def_id(item.id); @@ -5016,7 +5017,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { - self.collect_fn_info(sig, item.id); + self.collect_fn_info(sig, item.id, &item.attrs); } visit::walk_assoc_item(self, item, ctxt); } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index dec2a77619bad..ebd52026d37f8 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -489,7 +489,7 @@ impl RustcInternal for Safety { fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { match self { - Safety::Unsafe => rustc_hir::Safety::Unsafe, + Safety::Unsafe => rustc_hir::Safety::Unsafe { target_feature: false }, Safety::Safe => rustc_hir::Safety::Safe, } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs index 4f8da08eff916..5d03468207dda 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs @@ -15,7 +15,7 @@ impl<'tcx> Stable<'tcx> for rustc_hir::Safety { type T = stable_mir::mir::Safety; fn stable(&self, _: &mut Tables<'_>) -> Self::T { match self { - rustc_hir::Safety::Unsafe => stable_mir::mir::Safety::Unsafe, + rustc_hir::Safety::Unsafe { .. } => stable_mir::mir::Safety::Unsafe, rustc_hir::Safety::Safe => stable_mir::mir::Safety::Safe, } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index f10314c1c9e07..f9a165928858b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -207,7 +207,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let fn_sig = self_ty.fn_sig(self.tcx); let shortname = match fn_sig.safety() { hir::Safety::Safe => "fn", - hir::Safety::Unsafe => "unsafe fn", + hir::Safety::Unsafe { .. } => "unsafe fn", }; flags.push((sym::_Self, Some(shortname.to_owned()))); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index ced9ff2d68542..56dd4400e0d76 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -473,7 +473,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl { "" } - clean::ForeignStaticItem(_, hir::Safety::Unsafe) => { + clean::ForeignStaticItem(_, hir::Safety::Unsafe { .. }) => { "" } _ => "", diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index 40377dd841e0c..63db10350e399 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -33,7 +33,7 @@ pub fn check( let span = cx.tcx.def_span(owner_id); match (headers.safety, sig.header.safety) { - (false, Safety::Unsafe) => span_lint( + (false, Safety::Unsafe {..}) => span_lint( cx, MISSING_SAFETY_DOC, span, diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 88ac871acf688..e27dee9492132 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -631,7 +631,7 @@ impl<'tcx> LateLintPass<'tcx> for Documentation { } }, ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) { - (false, Safety::Unsafe) => span_lint( + (false, Safety::Unsafe { .. }) => span_lint( cx, MISSING_SAFETY_DOC, cx.tcx.def_span(item.owner_id), diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index b71b53ea3bbfd..748bf135a2ab5 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -252,9 +252,9 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")), ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), - ItemKind::Trait(_, Safety::Unsafe, ..) + ItemKind::Trait(_, Safety::Unsafe{..}, ..) | ItemKind::Impl(Impl { - safety: Safety::Unsafe, .. + safety: Safety::Unsafe{..}, .. }) => (Pat::Str("unsafe"), Pat::Str("}")), ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), diff --git a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr index db5895108bb0e..67baaf4fd367c 100644 --- a/tests/ui/async-await/async-closures/fn-exception-target-features.stderr +++ b/tests/ui/async-await/async-closures/fn-exception-target-features.stderr @@ -1,11 +1,12 @@ -error[E0277]: the trait bound `fn() -> Pin + 'static)>> {target_feature}: AsyncFn()` is not satisfied +error[E0277]: the trait bound `#[target_feature] fn() -> Pin + 'static)>> {target_feature}: AsyncFn()` is not satisfied --> $DIR/fn-exception-target-features.rs:16:10 | LL | test(target_feature); - | ---- ^^^^^^^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `fn() -> Pin + 'static)>> {target_feature}` + | ---- ^^^^^^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | + = help: the trait `AsyncFn()` is not implemented for fn item `#[target_feature] fn() -> Pin + 'static)>> {target_feature}` note: required by a bound in `test` --> $DIR/fn-exception-target-features.rs:13:17 | diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr index cc941be5479e3..c56eb92768230 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr @@ -10,13 +10,9 @@ LL | let foo: fn() = foo; | expected due to this | = note: expected fn pointer `fn()` - found fn item `fn() {foo}` - = note: fn items are distinct from fn pointers + found fn item `#[target_feature] fn() {foo}` = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers -help: consider casting to a fn pointer - | -LL | let foo: fn() = foo as fn(); - | ~~~~~~~~~~~ + = note: unsafe functions cannot be coerced into safe function pointers error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 3c370a1b8f321..3ad4cd1a4c7c5 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -21,9 +21,9 @@ fn call_once(f: impl FnOnce()) { } fn main() { - call(foo); //~ ERROR expected a `Fn()` closure, found `fn() {foo}` - call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `fn() {foo}` - call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `fn() {foo}` + call(foo); //~ ERROR expected a `Fn()` closure, found `#[target_feature] fn() {foo}` + call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `#[target_feature] fn() {foo}` + call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `#[target_feature] fn() {foo}` call(foo_unsafe); //~^ ERROR expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}` diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index 4c07f4d6b990d..654304f86be91 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,13 +1,14 @@ -error[E0277]: expected a `Fn()` closure, found `fn() {foo}` +error[E0277]: expected a `Fn()` closure, found `#[target_feature] fn() {foo}` --> $DIR/fn-traits.rs:24:10 | LL | call(foo); - | ---- ^^^ expected an `Fn()` closure, found `fn() {foo}` + | ---- ^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | - = help: the trait `Fn()` is not implemented for fn item `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = help: the trait `Fn()` is not implemented for fn item `#[target_feature] fn() {foo}` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `#[target_feature] fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call` --> $DIR/fn-traits.rs:11:17 @@ -15,16 +16,17 @@ note: required by a bound in `call` LL | fn call(f: impl Fn()) { | ^^^^ required by this bound in `call` -error[E0277]: expected a `FnMut()` closure, found `fn() {foo}` +error[E0277]: expected a `FnMut()` closure, found `#[target_feature] fn() {foo}` --> $DIR/fn-traits.rs:25:14 | LL | call_mut(foo); - | -------- ^^^ expected an `FnMut()` closure, found `fn() {foo}` + | -------- ^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | - = help: the trait `FnMut()` is not implemented for fn item `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = help: the trait `FnMut()` is not implemented for fn item `#[target_feature] fn() {foo}` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `#[target_feature] fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_mut` --> $DIR/fn-traits.rs:15:25 @@ -32,16 +34,17 @@ note: required by a bound in `call_mut` LL | fn call_mut(mut f: impl FnMut()) { | ^^^^^^^ required by this bound in `call_mut` -error[E0277]: expected a `FnOnce()` closure, found `fn() {foo}` +error[E0277]: expected a `FnOnce()` closure, found `#[target_feature] fn() {foo}` --> $DIR/fn-traits.rs:26:15 | LL | call_once(foo); - | --------- ^^^ expected an `FnOnce()` closure, found `fn() {foo}` + | --------- ^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | - = help: the trait `FnOnce()` is not implemented for fn item `fn() {foo}` - = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` + = help: the trait `FnOnce()` is not implemented for fn item `#[target_feature] fn() {foo}` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `#[target_feature] fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits note: required by a bound in `call_once` --> $DIR/fn-traits.rs:19:22 diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr index 1ddf05b40a606..4cfbdcdbef5b1 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr @@ -26,6 +26,9 @@ LL | Quux.avx_bmi2(); error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:38:5 | +LL | fn bar() { + | -------- items do not inherit unsafety from separate enclosing items +LL | sse2(); LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | @@ -34,6 +37,9 @@ LL | avx_bmi2(); error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:40:5 | +LL | fn bar() { + | -------- items do not inherit unsafety from separate enclosing items +... LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | @@ -42,6 +48,9 @@ LL | Quux.avx_bmi2(); error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:47:5 | +LL | fn baz() { + | -------- items do not inherit unsafety from separate enclosing items +LL | sse2(); LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` | @@ -50,6 +59,9 @@ LL | avx_bmi2(); error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block --> $DIR/safe-calls.rs:49:5 | +LL | fn baz() { + | -------- items do not inherit unsafety from separate enclosing items +... LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` | diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs index df575b0f6b636..a2ac6ff45fccf 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs @@ -13,6 +13,7 @@ impl Foo for Bar { #[target_feature(enable = "sse2")] //~^ ERROR cannot be applied to safe trait method fn foo(&self) {} + //~^ ERROR method `foo` has an incompatible type for trait #[target_feature(enable = "sse2")] unsafe fn unsf_foo(&self) {} diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr index 00efbb52f159b..de9c1e6bf9624 100644 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr +++ b/tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr @@ -1,3 +1,17 @@ +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/trait-impl.rs:15:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ expected safe fn, found #[target_feature] safe fn + | +note: type in trait + --> $DIR/trait-impl.rs:6:5 + | +LL | fn foo(&self); + | ^^^^^^^^^^^^^^ + = note: expected signature `fn(&Bar)` + found signature `#[target_feature] fn(&Bar)` + error: `#[target_feature(..)]` cannot be applied to safe trait method --> $DIR/trait-impl.rs:13:5 | @@ -8,7 +22,7 @@ LL | fn foo(&self) {} | ------------- not an `unsafe` function error: `#[target_feature(..)]` cannot be applied to safe trait method - --> $DIR/trait-impl.rs:22:5 + --> $DIR/trait-impl.rs:23:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method @@ -16,5 +30,6 @@ LL | LL | fn foo(&self) {} | ------------- not an `unsafe` function -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/target-feature/invalid-attribute.rs b/tests/ui/target-feature/invalid-attribute.rs index 2f951c4a00a9e..07bfba7c19c0c 100644 --- a/tests/ui/target-feature/invalid-attribute.rs +++ b/tests/ui/target-feature/invalid-attribute.rs @@ -97,6 +97,7 @@ impl Foo {} trait Quux { fn foo(); //~ NOTE `foo` from trait + //~^ NOTE: type in trait } impl Quux for Foo { @@ -106,6 +107,9 @@ impl Quux for Foo { //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date fn foo() {} //~^ NOTE not an `unsafe` function + //~| ERROR: incompatible type for trait + //~| NOTE: expected safe fn, found #[target_feature] safe fn + //~| NOTE: expected signature `fn()` } fn main() { diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index bf48911edec5f..b9a07c5063709 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -126,7 +126,7 @@ LL | impl Foo {} | ----------- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:112:5 + --> $DIR/invalid-attribute.rs:116:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL | | } | |_____- not a function definition error: attribute should be applied to a function definition - --> $DIR/invalid-attribute.rs:120:5 + --> $DIR/invalid-attribute.rs:124:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -192,8 +192,22 @@ LL | impl Quux for u8 {} LL | fn foo(); | --------- `foo` from trait +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/invalid-attribute.rs:108:5 + | +LL | fn foo() {} + | ^^^^^^^^ expected safe fn, found #[target_feature] safe fn + | +note: type in trait + --> $DIR/invalid-attribute.rs:99:5 + | +LL | fn foo(); + | ^^^^^^^^^ + = note: expected signature `fn()` + found signature `#[target_feature] fn()` + error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:103:5 + --> $DIR/invalid-attribute.rs:104:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +219,7 @@ LL | fn foo() {} = help: add `#![feature(target_feature_11)]` 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 23 previous errors +error: aborting due to 24 previous errors -Some errors have detailed explanations: E0046, E0658. +Some errors have detailed explanations: E0046, E0053, E0658. For more information about an error, try `rustc --explain E0046`.