Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 341f603

Browse files
committedJan 15, 2025
Auto merge of #134353 - oli-obk:safe-target-feature-unsafe-by-default, r=wesleywiser
Treat safe target_feature functions as unsafe by default [less invasive variant] This unblocks * #134090 As I stated in #134090 (comment) I think the previous impl was too easy to get wrong, as by default it treated safe target feature functions as safe and had to add additional checks for when they weren't. Now the logic is inverted. By default they are unsafe and you have to explicitly handle safe target feature functions. This is the less (imo) invasive variant of #134317, as it doesn't require changing the Safety enum, so it only affects FnDefs and nothing else, as it should.
2 parents 2776bdf + 767d4fe commit 341f603

File tree

39 files changed

+319
-120
lines changed

39 files changed

+319
-120
lines changed
 

‎compiler/rustc_ast_lowering/src/delegation.rs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
188188
) -> hir::FnSig<'hir> {
189189
let header = if let Some(local_sig_id) = sig_id.as_local() {
190190
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
191-
Some(sig) => self.lower_fn_header(sig.header, hir::Safety::Safe),
191+
Some(sig) => self.lower_fn_header(
192+
sig.header,
193+
// HACK: we override the default safety instead of generating attributes from the ether.
194+
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
195+
// and here we need the hir attributes.
196+
if sig.target_feature { hir::Safety::Unsafe } else { hir::Safety::Safe },
197+
&[],
198+
),
192199
None => self.generate_header_error(),
193200
}
194201
} else {
@@ -198,7 +205,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
198205
Asyncness::No => hir::IsAsync::NotAsync,
199206
};
200207
hir::FnHeader {
201-
safety: sig.safety,
208+
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
209+
hir::HeaderSafety::SafeTargetFeatures
210+
} else {
211+
hir::HeaderSafety::Normal(sig.safety)
212+
},
202213
constness: self.tcx.constness(sig_id),
203214
asyncness,
204215
abi: sig.abi,
@@ -384,7 +395,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
384395

385396
fn generate_header_error(&self) -> hir::FnHeader {
386397
hir::FnHeader {
387-
safety: hir::Safety::Safe,
398+
safety: hir::Safety::Safe.into(),
388399
constness: hir::Constness::NotConst,
389400
asyncness: hir::IsAsync::NotAsync,
390401
abi: abi::Abi::Rust,

‎compiler/rustc_ast_lowering/src/item.rs‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
231231
});
232232
let sig = hir::FnSig {
233233
decl,
234-
header: this.lower_fn_header(*header, hir::Safety::Safe),
234+
header: this.lower_fn_header(*header, hir::Safety::Safe, attrs),
235235
span: this.lower_span(*fn_sig_span),
236236
};
237237
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
@@ -610,7 +610,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
610610
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
611611
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
612612
let owner_id = hir_id.expect_owner();
613-
self.lower_attrs(hir_id, &i.attrs);
613+
let attrs = self.lower_attrs(hir_id, &i.attrs);
614614
let item = hir::ForeignItem {
615615
owner_id,
616616
ident: self.lower_ident(i.ident),
@@ -634,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
634634
});
635635

636636
// Unmarked safety in unsafe block defaults to unsafe.
637-
let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe);
637+
let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs);
638638

639639
hir::ForeignItemKind::Fn(
640640
hir::FnSig { header, decl, span: self.lower_span(sig.span) },
@@ -776,6 +776,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
776776
i.id,
777777
FnDeclKind::Trait,
778778
sig.header.coroutine_kind,
779+
attrs,
779780
);
780781
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
781782
}
@@ -795,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
795796
i.id,
796797
FnDeclKind::Trait,
797798
sig.header.coroutine_kind,
799+
attrs,
798800
);
799801
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
800802
}
@@ -911,6 +913,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
911913
i.id,
912914
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
913915
sig.header.coroutine_kind,
916+
attrs,
914917
);
915918

916919
(generics, hir::ImplItemKind::Fn(sig, body_id))
@@ -1339,8 +1342,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
13391342
id: NodeId,
13401343
kind: FnDeclKind,
13411344
coroutine_kind: Option<CoroutineKind>,
1345+
attrs: &[hir::Attribute],
13421346
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
1343-
let header = self.lower_fn_header(sig.header, hir::Safety::Safe);
1347+
let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs);
13441348
let itctx = ImplTraitContext::Universal;
13451349
let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
13461350
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
@@ -1352,14 +1356,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
13521356
&mut self,
13531357
h: FnHeader,
13541358
default_safety: hir::Safety,
1359+
attrs: &[hir::Attribute],
13551360
) -> hir::FnHeader {
13561361
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
13571362
hir::IsAsync::Async(span)
13581363
} else {
13591364
hir::IsAsync::NotAsync
13601365
};
1366+
1367+
let safety = self.lower_safety(h.safety, default_safety);
1368+
1369+
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
1370+
let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
1371+
&& safety.is_safe()
1372+
&& !self.tcx.sess.target.is_like_wasm
1373+
{
1374+
hir::HeaderSafety::SafeTargetFeatures
1375+
} else {
1376+
safety.into()
1377+
};
1378+
13611379
hir::FnHeader {
1362-
safety: self.lower_safety(h.safety, default_safety),
1380+
safety,
13631381
asyncness,
13641382
constness: self.lower_constness(h.constness),
13651383
abi: self.lower_extern(h.ext),

‎compiler/rustc_codegen_ssa/src/codegen_attrs.rs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
250250
}
251251
}
252252
sym::target_feature => {
253-
if !tcx.is_closure_like(did.to_def_id())
254-
&& let Some(fn_sig) = fn_sig()
255-
&& fn_sig.skip_binder().safety().is_safe()
256-
{
253+
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
254+
tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn");
255+
continue;
256+
};
257+
let safe_target_features =
258+
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
259+
codegen_fn_attrs.safe_target_features = safe_target_features;
260+
if safe_target_features {
257261
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
258262
// The `#[target_feature]` attribute is allowed on
259263
// WebAssembly targets on all functions, including safe

‎compiler/rustc_hir/src/hir.rs‎

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3762,9 +3762,30 @@ impl fmt::Display for Constness {
37623762
}
37633763
}
37643764

3765+
/// The actualy safety specified in syntax. We may treat
3766+
/// its safety different within the type system to create a
3767+
/// "sound by default" system that needs checking this enum
3768+
/// explicitly to allow unsafe operations.
3769+
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
3770+
pub enum HeaderSafety {
3771+
/// A safe function annotated with `#[target_features]`.
3772+
/// The type system treats this function as an unsafe function,
3773+
/// but safety checking will check this enum to treat it as safe
3774+
/// and allowing calling other safe target feature functions with
3775+
/// the same features without requiring an additional unsafe block.
3776+
SafeTargetFeatures,
3777+
Normal(Safety),
3778+
}
3779+
3780+
impl From<Safety> for HeaderSafety {
3781+
fn from(v: Safety) -> Self {
3782+
Self::Normal(v)
3783+
}
3784+
}
3785+
37653786
#[derive(Copy, Clone, Debug, HashStable_Generic)]
37663787
pub struct FnHeader {
3767-
pub safety: Safety,
3788+
pub safety: HeaderSafety,
37683789
pub constness: Constness,
37693790
pub asyncness: IsAsync,
37703791
pub abi: ExternAbi,
@@ -3780,7 +3801,18 @@ impl FnHeader {
37803801
}
37813802

37823803
pub fn is_unsafe(&self) -> bool {
3783-
self.safety.is_unsafe()
3804+
self.safety().is_unsafe()
3805+
}
3806+
3807+
pub fn is_safe(&self) -> bool {
3808+
self.safety().is_safe()
3809+
}
3810+
3811+
pub fn safety(&self) -> Safety {
3812+
match self.safety {
3813+
HeaderSafety::SafeTargetFeatures => Safety::Unsafe,
3814+
HeaderSafety::Normal(safety) => safety,
3815+
}
37843816
}
37853817
}
37863818

‎compiler/rustc_hir_analysis/src/collect.rs‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13361336
{
13371337
icx.lowerer().lower_fn_ty(
13381338
hir_id,
1339-
sig.header.safety,
1339+
sig.header.safety(),
13401340
sig.header.abi,
13411341
sig.decl,
13421342
Some(generics),
@@ -1351,13 +1351,18 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13511351
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
13521352
generics,
13531353
..
1354-
}) => {
1355-
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
1356-
}
1354+
}) => icx.lowerer().lower_fn_ty(
1355+
hir_id,
1356+
header.safety(),
1357+
header.abi,
1358+
decl,
1359+
Some(generics),
1360+
None,
1361+
),
13571362

13581363
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
13591364
let abi = tcx.hir().get_foreign_abi(hir_id);
1360-
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety)
1365+
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety())
13611366
}
13621367

13631368
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
@@ -1405,7 +1410,7 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
14051410

14061411
icx.lowerer().lower_fn_ty(
14071412
icx.tcx().local_def_id_to_hir_id(def_id),
1408-
sig.header.safety,
1413+
sig.header.safety(),
14091414
sig.header.abi,
14101415
sig.decl,
14111416
Some(generics),

‎compiler/rustc_hir_pretty/src/lib.rs‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,7 @@ impl<'a> State<'a> {
24072407
self.print_fn(
24082408
decl,
24092409
hir::FnHeader {
2410-
safety,
2410+
safety: safety.into(),
24112411
abi,
24122412
constness: hir::Constness::NotConst,
24132413
asyncness: hir::IsAsync::NotAsync,
@@ -2423,12 +2423,20 @@ impl<'a> State<'a> {
24232423
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
24242424
self.print_constness(header.constness);
24252425

2426+
let safety = match header.safety {
2427+
hir::HeaderSafety::SafeTargetFeatures => {
2428+
self.word_nbsp("#[target_feature]");
2429+
hir::Safety::Safe
2430+
}
2431+
hir::HeaderSafety::Normal(safety) => safety,
2432+
};
2433+
24262434
match header.asyncness {
24272435
hir::IsAsync::NotAsync => {}
24282436
hir::IsAsync::Async(_) => self.word_nbsp("async"),
24292437
}
24302438

2431-
self.print_safety(header.safety);
2439+
self.print_safety(safety);
24322440

24332441
if header.abi != ExternAbi::Rust {
24342442
self.word_nbsp("extern");

‎compiler/rustc_hir_typeck/src/coercion.rs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,10 +932,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932932
return Err(TypeError::ForceInlineCast);
933933
}
934934

935-
// Safe `#[target_feature]` functions are not assignable to safe fn pointers
936-
// (RFC 2396).
935+
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
936+
if matches!(fn_attrs.inline, InlineAttr::Force { .. }) {
937+
return Err(TypeError::ForceInlineCast);
938+
}
939+
940+
// FIXME(target_feature): Safe `#[target_feature]` functions could be cast to safe fn pointers (RFC 2396),
941+
// as you can already write that "cast" in user code by wrapping a target_feature fn call in a closure,
942+
// which is safe. This is sound because you already need to be executing code that is satisfying the target
943+
// feature constraints..
937944
if b_hdr.safety.is_safe()
938-
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
945+
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
939946
{
940947
return Err(TypeError::TargetFeatureCast(def_id));
941948
}

‎compiler/rustc_hir_typeck/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ fn typeck_with_fallback<'tcx>(
139139
// type that has an infer in it, lower the type directly so that it'll
140140
// be correctly filled with infer. We'll use this inference to provide
141141
// a suggestion later on.
142-
fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl, None, None)
142+
fcx.lowerer().lower_fn_ty(id, header.safety(), header.abi, decl, None, None)
143143
} else {
144144
tcx.fn_sig(def_id).instantiate_identity()
145145
};

‎compiler/rustc_middle/src/middle/codegen_fn_attrs.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub struct CodegenFnAttrs {
3030
/// features (only enabled features are supported right now).
3131
/// Implied target features have already been applied.
3232
pub target_features: Vec<TargetFeature>,
33+
/// Whether the function was declared safe, but has target features
34+
pub safe_target_features: bool,
3335
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3436
pub linkage: Option<Linkage>,
3537
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -150,6 +152,7 @@ impl CodegenFnAttrs {
150152
link_name: None,
151153
link_ordinal: None,
152154
target_features: vec![],
155+
safe_target_features: false,
153156
linkage: None,
154157
import_linkage: None,
155158
link_section: None,

‎compiler/rustc_middle/src/ty/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ pub struct DelegationFnSig {
222222
pub param_count: usize,
223223
pub has_self: bool,
224224
pub c_variadic: bool,
225+
pub target_feature: bool,
225226
}
226227

227228
#[derive(Clone, Copy, Debug)]

‎compiler/rustc_middle/src/ty/print/pretty.rs‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
690690
if with_reduced_queries() {
691691
p!(print_def_path(def_id, args));
692692
} else {
693-
let sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
693+
let mut sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
694+
if self.tcx().codegen_fn_attrs(def_id).safe_target_features {
695+
p!("#[target_features] ");
696+
sig = sig.map_bound(|mut sig| {
697+
sig.safety = hir::Safety::Safe;
698+
sig
699+
});
700+
}
694701
p!(print(sig), " {{", print_value_path(def_id, args), "}}");
695702
}
696703
}

‎compiler/rustc_mir_build/src/check_unsafety.rs‎

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -478,19 +478,27 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
478478
return; // don't visit the whole expression
479479
}
480480
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
481-
if self.thir[fun].ty.fn_sig(self.tcx).safety().is_unsafe() {
482-
let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
481+
let fn_ty = self.thir[fun].ty;
482+
let sig = fn_ty.fn_sig(self.tcx);
483+
let (callee_features, safe_target_features): (&[_], _) = match fn_ty.kind() {
484+
ty::FnDef(func_id, ..) => {
485+
let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
486+
(&cg_attrs.target_features, cg_attrs.safe_target_features)
487+
}
488+
_ => (&[], false),
489+
};
490+
if sig.safety().is_unsafe() && !safe_target_features {
491+
let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
483492
Some(*func_id)
484493
} else {
485494
None
486495
};
487496
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
488-
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
497+
} else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
489498
// If the called function has target features the calling function hasn't,
490499
// the call requires `unsafe`. Don't check this on wasm
491500
// targets, though. For more information on wasm see the
492501
// is_like_wasm check in hir_analysis/src/collect.rs
493-
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
494502
if !self.tcx.sess.target.options.is_like_wasm
495503
&& !callee_features.iter().all(|feature| {
496504
self.body_target_features.iter().any(|f| f.name == feature.name)
@@ -739,7 +747,10 @@ impl UnsafeOpKind {
739747
) {
740748
let parent_id = tcx.hir().get_parent_item(hir_id);
741749
let parent_owner = tcx.hir_owner_node(parent_id);
742-
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| sig.header.is_unsafe());
750+
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
751+
// Do not suggest for safe target_feature functions
752+
matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
753+
});
743754
let unsafe_not_inherited_note = if should_suggest {
744755
suggest_unsafe_block.then(|| {
745756
let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span;
@@ -902,7 +913,7 @@ impl UnsafeOpKind {
902913
{
903914
true
904915
} else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
905-
&& sig.header.is_unsafe()
916+
&& matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
906917
{
907918
true
908919
} else {
@@ -1111,7 +1122,16 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
11111122

11121123
let hir_id = tcx.local_def_id_to_hir_id(def);
11131124
let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1114-
if fn_sig.header.safety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }
1125+
match fn_sig.header.safety {
1126+
// We typeck the body as safe, but otherwise treat it as unsafe everywhere else.
1127+
// Call sites to other SafeTargetFeatures functions are checked explicitly and don't need
1128+
// to care about safety of the body.
1129+
hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1130+
hir::HeaderSafety::Normal(safety) => match safety {
1131+
hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1132+
hir::Safety::Safe => SafetyContext::Safe,
1133+
},
1134+
}
11151135
});
11161136
let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
11171137
let mut warnings = Vec::new();

‎compiler/rustc_resolve/src/late.rs‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5019,12 +5019,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
50195019
}
50205020

50215021
impl ItemInfoCollector<'_, '_, '_> {
5022-
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId) {
5022+
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) {
50235023
let sig = DelegationFnSig {
50245024
header: sig.header,
50255025
param_count: sig.decl.inputs.len(),
50265026
has_self: sig.decl.has_self(),
50275027
c_variadic: sig.decl.c_variadic(),
5028+
target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)),
50285029
};
50295030
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
50305031
}
@@ -5043,7 +5044,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
50435044
| ItemKind::Trait(box Trait { ref generics, .. })
50445045
| ItemKind::TraitAlias(ref generics, _) => {
50455046
if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
5046-
self.collect_fn_info(sig, item.id);
5047+
self.collect_fn_info(sig, item.id, &item.attrs);
50475048
}
50485049

50495050
let def_id = self.r.local_def_id(item.id);
@@ -5076,7 +5077,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
50765077

50775078
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
50785079
if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
5079-
self.collect_fn_info(sig, item.id);
5080+
self.collect_fn_info(sig, item.id, &item.attrs);
50805081
}
50815082
visit::walk_assoc_item(self, item, ctxt);
50825083
}

‎compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs‎

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -824,9 +824,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
824824
fn cmp_fn_sig(
825825
&self,
826826
sig1: &ty::PolyFnSig<'tcx>,
827-
fn_def1: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
827+
fn_def1: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
828828
sig2: &ty::PolyFnSig<'tcx>,
829-
fn_def2: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
829+
fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
830830
) -> (DiagStyledString, DiagStyledString) {
831831
let sig1 = &(self.normalize_fn_sig)(*sig1);
832832
let sig2 = &(self.normalize_fn_sig)(*sig2);
@@ -850,8 +850,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
850850

851851
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
852852
// ^^^^^^
853-
values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
854-
values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
853+
let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
854+
None => sig.safety.prefix_str(),
855+
Some((did, _)) => {
856+
if self.tcx.codegen_fn_attrs(did).safe_target_features {
857+
"#[target_features] "
858+
} else {
859+
sig.safety.prefix_str()
860+
}
861+
}
862+
};
863+
let safety1 = safety(fn_def1, sig1);
864+
let safety2 = safety(fn_def2, sig2);
865+
values.0.push(safety1, safety1 != safety2);
866+
values.1.push(safety2, safety1 != safety2);
855867

856868
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
857869
// ^^^^^^^^^^
@@ -932,23 +944,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
932944
(values.1).0.extend(x2.0);
933945
}
934946

935-
let fmt = |(did, args)| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
947+
let fmt = |did, args| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
936948

937949
match (fn_def1, fn_def2) {
938-
(None, None) => {}
939-
(Some(fn_def1), Some(fn_def2)) => {
940-
let path1 = fmt(fn_def1);
941-
let path2 = fmt(fn_def2);
950+
(Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
951+
let path1 = fmt(fn_def1, fn_args1);
952+
let path2 = fmt(fn_def2, fn_args2);
942953
let same_path = path1 == path2;
943954
values.0.push(path1, !same_path);
944955
values.1.push(path2, !same_path);
945956
}
946-
(Some(fn_def1), None) => {
947-
values.0.push_highlighted(fmt(fn_def1));
957+
(Some((fn_def1, Some(fn_args1))), None) => {
958+
values.0.push_highlighted(fmt(fn_def1, fn_args1));
948959
}
949-
(None, Some(fn_def2)) => {
950-
values.1.push_highlighted(fmt(fn_def2));
960+
(None, Some((fn_def2, Some(fn_args2)))) => {
961+
values.1.push_highlighted(fmt(fn_def2, fn_args2));
951962
}
963+
_ => {}
952964
}
953965

954966
values
@@ -1339,17 +1351,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
13391351
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
13401352
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
13411353
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1342-
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig2, Some((*did2, args2)))
1354+
self.cmp_fn_sig(
1355+
&sig1,
1356+
Some((*did1, Some(args1))),
1357+
&sig2,
1358+
Some((*did2, Some(args2))),
1359+
)
13431360
}
13441361

13451362
(ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
13461363
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
1347-
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig_tys2.with(*hdr2), None)
1364+
self.cmp_fn_sig(&sig1, Some((*did1, Some(args1))), &sig_tys2.with(*hdr2), None)
13481365
}
13491366

13501367
(ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
13511368
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
1352-
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, args2)))
1369+
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, Some(args2))))
13531370
}
13541371

13551372
(ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
@@ -1531,7 +1548,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
15311548
(false, Mismatch::Fixed("existential projection"))
15321549
}
15331550
};
1534-
let Some(vals) = self.values_str(values) else {
1551+
let Some(vals) = self.values_str(values, cause) else {
15351552
// Derived error. Cancel the emitter.
15361553
// NOTE(eddyb) this was `.cancel()`, but `diag`
15371554
// is borrowed, so we can't fully defuse it.
@@ -1956,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
19561973
})
19571974
| ObligationCauseCode::BlockTailExpression(.., source)) = code
19581975
&& let hir::MatchSource::TryDesugar(_) = source
1959-
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values)
1976+
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
19601977
{
19611978
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
19621979
found: found_ty.content(),
@@ -2085,6 +2102,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
20852102
fn values_str(
20862103
&self,
20872104
values: ValuePairs<'tcx>,
2105+
cause: &ObligationCause<'tcx>,
20882106
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
20892107
match values {
20902108
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
@@ -2109,7 +2127,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
21092127
if exp_found.references_error() {
21102128
return None;
21112129
}
2112-
let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, None, &exp_found.found, None);
2130+
let (fn_def1, fn_def2) = if let ObligationCauseCode::CompareImplItem {
2131+
impl_item_def_id,
2132+
trait_item_def_id,
2133+
..
2134+
} = *cause.code()
2135+
{
2136+
(Some((trait_item_def_id, None)), Some((impl_item_def_id.to_def_id(), None)))
2137+
} else {
2138+
(None, None)
2139+
};
2140+
2141+
let (exp, fnd) =
2142+
self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
21132143
Some((exp, fnd, None))
21142144
}
21152145
}

‎compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,11 @@ impl<T> Trait<T> for X {
461461
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
462462
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
463463
if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety {
464-
diag.note(
464+
if !tcx.codegen_fn_attrs(def_id).safe_target_features {
465+
diag.note(
465466
"unsafe functions cannot be coerced into safe function pointers",
466-
);
467+
);
468+
}
467469
}
468470
}
469471
(ty::Adt(_, _), ty::Adt(def, args))

‎compiler/rustc_trait_selection/src/error_reporting/infer/region.rs‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
221221
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
222222
span: trace.cause.span,
223223
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
224-
expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
224+
expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
225225
}
226226
.add_to_diag(err),
227227
infer::Reborrow(span) => {
@@ -946,8 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
946946

947947
if let infer::Subtype(ref sup_trace) = sup_origin
948948
&& let infer::Subtype(ref sub_trace) = sub_origin
949-
&& let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
950-
&& let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
949+
&& let Some((sup_expected, sup_found, _)) =
950+
self.values_str(sup_trace.values, &sup_trace.cause)
951+
&& let Some((sub_expected, sub_found, _)) =
952+
self.values_str(sub_trace.values, &sup_trace.cause)
951953
&& sub_expected == sup_expected
952954
&& sub_found == sup_found
953955
{

‎compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
205205

206206
if self_ty.is_fn() {
207207
let fn_sig = self_ty.fn_sig(self.tcx);
208-
let shortname = match fn_sig.safety() {
209-
hir::Safety::Safe => "fn",
210-
hir::Safety::Unsafe => "unsafe fn",
208+
let shortname = if let ty::FnDef(def_id, _) = self_ty.kind()
209+
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
210+
{
211+
"#[target_feature] fn"
212+
} else {
213+
match fn_sig.safety() {
214+
hir::Safety::Safe => "fn",
215+
hir::Safety::Unsafe => "unsafe fn",
216+
}
211217
};
212218
flags.push((sym::_Self, Some(shortname.to_owned())));
213219
}

‎src/librustdoc/clean/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3094,7 +3094,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
30943094
let kind = match item.kind {
30953095
hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
30963096
clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
3097-
sig.header.safety,
3097+
sig.header.safety(),
30983098
),
30993099
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
31003100
Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None },

‎src/librustdoc/clean/types.rs‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -668,17 +668,28 @@ impl Item {
668668
ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
669669
ty::Asyncness::No => hir::IsAsync::NotAsync,
670670
};
671-
hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
671+
hir::FnHeader {
672+
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
673+
hir::HeaderSafety::SafeTargetFeatures
674+
} else {
675+
sig.safety().into()
676+
},
677+
abi: sig.abi(),
678+
constness,
679+
asyncness,
680+
}
672681
}
673682
let header = match self.kind {
674683
ItemKind::ForeignFunctionItem(_, safety) => {
675684
let def_id = self.def_id().unwrap();
676685
let abi = tcx.fn_sig(def_id).skip_binder().abi();
677686
hir::FnHeader {
678-
safety: if abi == ExternAbi::RustIntrinsic {
679-
intrinsic_operation_unsafety(tcx, def_id.expect_local())
687+
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
688+
hir::HeaderSafety::SafeTargetFeatures
689+
} else if abi == ExternAbi::RustIntrinsic {
690+
intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
680691
} else {
681-
safety
692+
safety.into()
682693
},
683694
abi,
684695
constness: if tcx.is_const_fn(def_id) {

‎src/librustdoc/html/format.rs‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,15 @@ impl PrintWithSpace for hir::Safety {
16371637
}
16381638
}
16391639

1640+
impl PrintWithSpace for hir::HeaderSafety {
1641+
fn print_with_space(&self) -> &str {
1642+
match self {
1643+
hir::HeaderSafety::SafeTargetFeatures => "",
1644+
hir::HeaderSafety::Normal(safety) => safety.print_with_space(),
1645+
}
1646+
}
1647+
}
1648+
16401649
impl PrintWithSpace for hir::IsAsync {
16411650
fn print_with_space(&self) -> &str {
16421651
match self {

‎src/librustdoc/html/render/print_item.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
469469

470470
let unsafety_flag = match myitem.kind {
471471
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
472-
if myitem.fn_header(tcx).unwrap().safety.is_unsafe() =>
472+
if myitem.fn_header(tcx).unwrap().is_unsafe() =>
473473
{
474474
"<sup title=\"unsafe function\">⚠</sup>"
475475
}

‎src/tools/clippy/clippy_lints/src/derive.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
419419
id: LocalDefId,
420420
) -> Self::Result {
421421
if let Some(header) = kind.header()
422-
&& header.safety.is_unsafe()
422+
&& header.is_unsafe()
423423
{
424424
ControlFlow::Break(())
425425
} else {

‎src/tools/clippy/clippy_lints/src/doc/missing_headers.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn check(
3232
}
3333

3434
let span = cx.tcx.def_span(owner_id);
35-
match (headers.safety, sig.header.safety) {
35+
match (headers.safety, sig.header.safety()) {
3636
(false, Safety::Unsafe) => span_lint(
3737
cx,
3838
MISSING_SAFETY_DOC,

‎src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
3434
ImplicitSelfKind::None => return,
3535
};
3636

37-
let name = if sig.header.safety.is_unsafe() {
37+
let name = if sig.header.is_unsafe() {
3838
name.strip_suffix("_unchecked").unwrap_or(name)
3939
} else {
4040
name

‎src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pub(super) fn check_fn<'tcx>(
2020
def_id: LocalDefId,
2121
) {
2222
let safety = match kind {
23-
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
24-
intravisit::FnKind::Method(_, sig) => sig.header.safety,
23+
intravisit::FnKind::ItemFn(_, _, header) => header.safety(),
24+
intravisit::FnKind::Method(_, sig) => sig.header.safety(),
2525
intravisit::FnKind::Closure => return,
2626
};
2727

@@ -31,7 +31,7 @@ pub(super) fn check_fn<'tcx>(
3131
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
3232
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
3333
let body = cx.tcx.hir().body(eid);
34-
check_raw_ptr(cx, sig.header.safety, sig.decl, body, item.owner_id.def_id);
34+
check_raw_ptr(cx, sig.header.safety(), sig.decl, body, item.owner_id.def_id);
3535
}
3636
}
3737

‎src/tools/clippy/clippy_lints/src/inherent_to_string.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
9595
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
9696
// #11201
9797
&& let header = signature.header
98-
&& header.safety.is_safe()
98+
&& header.is_safe()
9999
&& header.abi == Abi::Rust
100100
&& impl_item.ident.name == sym::to_string
101101
&& let decl = signature.decl

‎src/tools/clippy/clippy_lints/src/methods/mod.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5309,7 +5309,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
53095309
}
53105310

53115311
const FN_HEADER: hir::FnHeader = hir::FnHeader {
5312-
safety: hir::Safety::Safe,
5312+
safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
53135313
constness: hir::Constness::NotConst,
53145314
asyncness: hir::IsAsync::NotAsync,
53155315
abi: rustc_target::spec::abi::Abi::Rust,

‎src/tools/clippy/clippy_lints/src/new_without_default.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
7575
if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
7676
let name = impl_item.ident.name;
7777
let id = impl_item.owner_id;
78-
if sig.header.safety.is_unsafe() {
78+
if sig.header.is_unsafe() {
7979
// can't be implemented for unsafe new
8080
return;
8181
}

‎src/tools/clippy/clippy_lints/src/ptr.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
541541
.collect();
542542
if let Some(args) = args
543543
&& !args.is_empty()
544-
&& body.is_none_or(|body| sig.header.safety.is_unsafe() || contains_unsafe_block(cx, body.value))
544+
&& body.is_none_or(|body| sig.header.is_unsafe() || contains_unsafe_block(cx, body.value))
545545
{
546546
span_lint_and_then(
547547
cx,

‎tests/ui/async-await/async-closures/fn-exception-target-features.stderr‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn()` is not satisfied
1+
error[E0277]: the trait bound `#[target_features] fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn()` is not satisfied
22
--> $DIR/fn-exception-target-features.rs:16:10
33
|
44
LL | test(target_feature);
5-
| ---- ^^^^^^^^^^^^^^ the trait `AsyncFn()` is not implemented for fn item `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
5+
| ---- ^^^^^^^^^^^^^^ unsatisfied trait bound
66
| |
77
| required by a bound introduced by this call
88
|
9+
= help: the trait `AsyncFn()` is not implemented for fn item `#[target_features] fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
910
note: required by a bound in `test`
1011
--> $DIR/fn-exception-target-features.rs:13:17
1112
|

‎tests/ui/macros/issue-68060.rs‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ fn main() {
33
.map(
44
#[target_feature(enable = "")]
55
//~^ ERROR: attribute should be applied to a function
6-
//~| ERROR: feature named `` is not valid
7-
//~| NOTE: `` is not valid for this target
86
#[track_caller]
97
//~^ ERROR: `#[track_caller]` on closures is currently unstable
108
//~| NOTE: see issue #87417

‎tests/ui/macros/issue-68060.stderr‎

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,8 @@ LL | #[target_feature(enable = "")]
77
LL | |_| (),
88
| ------ not a function definition
99

10-
error: the feature named `` is not valid for this target
11-
--> $DIR/issue-68060.rs:4:30
12-
|
13-
LL | #[target_feature(enable = "")]
14-
| ^^^^^^^^^^^ `` is not valid for this target
15-
1610
error[E0658]: `#[track_caller]` on closures is currently unstable
17-
--> $DIR/issue-68060.rs:8:13
11+
--> $DIR/issue-68060.rs:6:13
1812
|
1913
LL | #[track_caller]
2014
| ^^^^^^^^^^^^^^^
@@ -23,6 +17,6 @@ LL | #[track_caller]
2317
= help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
2418
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
2519

26-
error: aborting due to 3 previous errors
20+
error: aborting due to 2 previous errors
2721

2822
For more information about this error, try `rustc --explain E0658`.

‎tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,8 @@ LL | let foo: fn() = foo;
1010
| expected due to this
1111
|
1212
= note: expected fn pointer `fn()`
13-
found fn item `fn() {foo}`
14-
= note: fn items are distinct from fn pointers
13+
found fn item `#[target_features] fn() {foo}`
1514
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
16-
help: consider casting to a fn pointer
17-
|
18-
LL | let foo: fn() = foo as fn();
19-
| ~~~~~~~~~~~
2015

2116
error: aborting due to 1 previous error
2217

‎tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ fn call_once(f: impl FnOnce()) {
2121
}
2222

2323
fn main() {
24-
call(foo); //~ ERROR expected a `Fn()` closure, found `fn() {foo}`
25-
call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `fn() {foo}`
26-
call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `fn() {foo}`
24+
call(foo); //~ ERROR expected a `Fn()` closure, found `#[target_features] fn() {foo}`
25+
call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `#[target_features] fn() {foo}`
26+
call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `#[target_features] fn() {foo}`
2727

2828
call(foo_unsafe);
2929
//~^ ERROR expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}`

‎tests/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,47 @@
1-
error[E0277]: expected a `Fn()` closure, found `fn() {foo}`
1+
error[E0277]: expected a `Fn()` closure, found `#[target_features] fn() {foo}`
22
--> $DIR/fn-traits.rs:24:10
33
|
44
LL | call(foo);
5-
| ---- ^^^ expected an `Fn()` closure, found `fn() {foo}`
5+
| ---- ^^^ expected an `Fn()` closure, found `#[target_features] fn() {foo}`
66
| |
77
| required by a bound introduced by this call
88
|
9-
= help: the trait `Fn()` is not implemented for fn item `fn() {foo}`
10-
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
9+
= help: the trait `Fn()` is not implemented for fn item `#[target_features] fn() {foo}`
10+
= note: wrap the `#[target_features] fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
1111
= note: `#[target_feature]` functions do not implement the `Fn` traits
1212
note: required by a bound in `call`
1313
--> $DIR/fn-traits.rs:11:17
1414
|
1515
LL | fn call(f: impl Fn()) {
1616
| ^^^^ required by this bound in `call`
1717

18-
error[E0277]: expected a `FnMut()` closure, found `fn() {foo}`
18+
error[E0277]: expected a `FnMut()` closure, found `#[target_features] fn() {foo}`
1919
--> $DIR/fn-traits.rs:25:14
2020
|
2121
LL | call_mut(foo);
22-
| -------- ^^^ expected an `FnMut()` closure, found `fn() {foo}`
22+
| -------- ^^^ expected an `FnMut()` closure, found `#[target_features] fn() {foo}`
2323
| |
2424
| required by a bound introduced by this call
2525
|
26-
= help: the trait `FnMut()` is not implemented for fn item `fn() {foo}`
27-
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
26+
= help: the trait `FnMut()` is not implemented for fn item `#[target_features] fn() {foo}`
27+
= note: wrap the `#[target_features] fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
2828
= note: `#[target_feature]` functions do not implement the `Fn` traits
2929
note: required by a bound in `call_mut`
3030
--> $DIR/fn-traits.rs:15:25
3131
|
3232
LL | fn call_mut(mut f: impl FnMut()) {
3333
| ^^^^^^^ required by this bound in `call_mut`
3434

35-
error[E0277]: expected a `FnOnce()` closure, found `fn() {foo}`
35+
error[E0277]: expected a `FnOnce()` closure, found `#[target_features] fn() {foo}`
3636
--> $DIR/fn-traits.rs:26:15
3737
|
3838
LL | call_once(foo);
39-
| --------- ^^^ expected an `FnOnce()` closure, found `fn() {foo}`
39+
| --------- ^^^ expected an `FnOnce()` closure, found `#[target_features] fn() {foo}`
4040
| |
4141
| required by a bound introduced by this call
4242
|
43-
= help: the trait `FnOnce()` is not implemented for fn item `fn() {foo}`
44-
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
43+
= help: the trait `FnOnce()` is not implemented for fn item `#[target_features] fn() {foo}`
44+
= note: wrap the `#[target_features] fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
4545
= note: `#[target_feature]` functions do not implement the `Fn` traits
4646
note: required by a bound in `call_once`
4747
--> $DIR/fn-traits.rs:19:22

‎tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ impl Foo for Bar {
1313
#[target_feature(enable = "sse2")]
1414
//~^ ERROR cannot be applied to safe trait method
1515
fn foo(&self) {}
16+
//~^ ERROR method `foo` has an incompatible type for trait
1617

1718
#[target_feature(enable = "sse2")]
1819
unsafe fn unsf_foo(&self) {}

‎tests/ui/rfcs/rfc-2396-target_feature-11/trait-impl.stderr‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,29 @@ LL |
77
LL | fn foo(&self) {}
88
| ------------- not an `unsafe` function
99

10+
error[E0053]: method `foo` has an incompatible type for trait
11+
--> $DIR/trait-impl.rs:15:5
12+
|
13+
LL | fn foo(&self) {}
14+
| ^^^^^^^^^^^^^ expected safe fn, found unsafe fn
15+
|
16+
note: type in trait
17+
--> $DIR/trait-impl.rs:6:5
18+
|
19+
LL | fn foo(&self);
20+
| ^^^^^^^^^^^^^^
21+
= note: expected signature `fn(&Bar)`
22+
found signature `#[target_features] fn(&Bar)`
23+
1024
error: `#[target_feature(..)]` cannot be applied to safe trait method
11-
--> $DIR/trait-impl.rs:22:5
25+
--> $DIR/trait-impl.rs:23:5
1226
|
1327
LL | #[target_feature(enable = "sse2")]
1428
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
1529
LL |
1630
LL | fn foo(&self) {}
1731
| ------------- not an `unsafe` function
1832

19-
error: aborting due to 2 previous errors
33+
error: aborting due to 3 previous errors
2034

35+
For more information about this error, try `rustc --explain E0053`.

‎tests/ui/target-feature/invalid-attribute.rs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl Foo {}
9797

9898
trait Quux {
9999
fn foo(); //~ NOTE `foo` from trait
100+
//~^ NOTE: type in trait
100101
}
101102

102103
impl Quux for Foo {
@@ -106,6 +107,9 @@ impl Quux for Foo {
106107
//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
107108
fn foo() {}
108109
//~^ NOTE not an `unsafe` function
110+
//~| ERROR: incompatible type for trait
111+
//~| NOTE: expected safe fn, found unsafe fn
112+
//~| NOTE: expected signature `fn()`
109113
}
110114

111115
fn main() {

‎tests/ui/target-feature/invalid-attribute.stderr‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ LL | impl Foo {}
126126
| ----------- not a function definition
127127

128128
error: attribute should be applied to a function definition
129-
--> $DIR/invalid-attribute.rs:112:5
129+
--> $DIR/invalid-attribute.rs:116:5
130130
|
131131
LL | #[target_feature(enable = "sse2")]
132132
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@ LL | | }
138138
| |_____- not a function definition
139139

140140
error: attribute should be applied to a function definition
141-
--> $DIR/invalid-attribute.rs:120:5
141+
--> $DIR/invalid-attribute.rs:124:5
142142
|
143143
LL | #[target_feature(enable = "sse2")]
144144
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL | fn foo();
193193
| --------- `foo` from trait
194194

195195
error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
196-
--> $DIR/invalid-attribute.rs:103:5
196+
--> $DIR/invalid-attribute.rs:104:5
197197
|
198198
LL | #[target_feature(enable = "sse2")]
199199
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,7 +205,21 @@ LL | fn foo() {}
205205
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
206206
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
207207

208-
error: aborting due to 23 previous errors
208+
error[E0053]: method `foo` has an incompatible type for trait
209+
--> $DIR/invalid-attribute.rs:108:5
210+
|
211+
LL | fn foo() {}
212+
| ^^^^^^^^ expected safe fn, found unsafe fn
213+
|
214+
note: type in trait
215+
--> $DIR/invalid-attribute.rs:99:5
216+
|
217+
LL | fn foo();
218+
| ^^^^^^^^^
219+
= note: expected signature `fn()`
220+
found signature `#[target_features] fn()`
221+
222+
error: aborting due to 24 previous errors
209223

210-
Some errors have detailed explanations: E0046, E0658.
224+
Some errors have detailed explanations: E0046, E0053, E0658.
211225
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)
Please sign in to comment.