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 https://github.com/rust-lang/rust/pull/134090#issuecomment-2541332415 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.
This commit is contained in:
commit
341f60327f
39 changed files with 319 additions and 120 deletions
|
@ -188,7 +188,14 @@ 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,
|
||||
// HACK: we override the default safety instead of generating attributes from the ether.
|
||||
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
|
||||
// and here we need the hir attributes.
|
||||
if sig.target_feature { hir::Safety::Unsafe } else { hir::Safety::Safe },
|
||||
&[],
|
||||
),
|
||||
None => self.generate_header_error(),
|
||||
}
|
||||
} else {
|
||||
|
@ -198,7 +205,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
hir::FnHeader {
|
||||
safety: sig.safety,
|
||||
safety: if self.tcx.codegen_fn_attrs(sig_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
hir::HeaderSafety::Normal(sig.safety)
|
||||
},
|
||||
constness: self.tcx.constness(sig_id),
|
||||
asyncness,
|
||||
abi: sig.abi,
|
||||
|
@ -384,7 +395,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
fn generate_header_error(&self) -> hir::FnHeader {
|
||||
hir::FnHeader {
|
||||
safety: hir::Safety::Safe,
|
||||
safety: hir::Safety::Safe.into(),
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
abi: abi::Abi::Rust,
|
||||
|
|
|
@ -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: body_id, has_body: body.is_some() }
|
||||
|
@ -610,7 +610,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),
|
||||
|
@ -634,7 +634,7 @@ 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, attrs);
|
||||
|
||||
hir::ForeignItemKind::Fn(
|
||||
hir::FnSig { header, decl, span: self.lower_span(sig.span) },
|
||||
|
@ -776,6 +776,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
i.id,
|
||||
FnDeclKind::Trait,
|
||||
sig.header.coroutine_kind,
|
||||
attrs,
|
||||
);
|
||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||
}
|
||||
|
@ -795,6 +796,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)
|
||||
}
|
||||
|
@ -911,6 +913,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))
|
||||
|
@ -1339,8 +1342,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
id: NodeId,
|
||||
kind: FnDeclKind,
|
||||
coroutine_kind: Option<CoroutineKind>,
|
||||
attrs: &[hir::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)
|
||||
|
@ -1352,14 +1356,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
h: FnHeader,
|
||||
default_safety: hir::Safety,
|
||||
attrs: &[hir::Attribute],
|
||||
) -> hir::FnHeader {
|
||||
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
|
||||
hir::IsAsync::Async(span)
|
||||
} else {
|
||||
hir::IsAsync::NotAsync
|
||||
};
|
||||
|
||||
let safety = self.lower_safety(h.safety, default_safety);
|
||||
|
||||
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
|
||||
let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
|
||||
&& safety.is_safe()
|
||||
&& !self.tcx.sess.target.is_like_wasm
|
||||
{
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
safety.into()
|
||||
};
|
||||
|
||||
hir::FnHeader {
|
||||
safety: self.lower_safety(h.safety, default_safety),
|
||||
safety,
|
||||
asyncness,
|
||||
constness: self.lower_constness(h.constness),
|
||||
abi: self.lower_extern(h.ext),
|
||||
|
|
|
@ -250,10 +250,14 @@ 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()
|
||||
{
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn");
|
||||
continue;
|
||||
};
|
||||
let safe_target_features =
|
||||
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
|
||||
codegen_fn_attrs.safe_target_features = safe_target_features;
|
||||
if safe_target_features {
|
||||
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||
// The `#[target_feature]` attribute is allowed on
|
||||
// WebAssembly targets on all functions, including safe
|
||||
|
|
|
@ -3762,9 +3762,30 @@ impl fmt::Display for Constness {
|
|||
}
|
||||
}
|
||||
|
||||
/// The actualy safety specified in syntax. We may treat
|
||||
/// its safety different within the type system to create a
|
||||
/// "sound by default" system that needs checking this enum
|
||||
/// explicitly to allow unsafe operations.
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic, PartialEq, Eq)]
|
||||
pub enum HeaderSafety {
|
||||
/// A safe function annotated with `#[target_features]`.
|
||||
/// The type system treats this function as an unsafe function,
|
||||
/// but safety checking will check this enum to treat it as safe
|
||||
/// and allowing calling other safe target feature functions with
|
||||
/// the same features without requiring an additional unsafe block.
|
||||
SafeTargetFeatures,
|
||||
Normal(Safety),
|
||||
}
|
||||
|
||||
impl From<Safety> for HeaderSafety {
|
||||
fn from(v: Safety) -> Self {
|
||||
Self::Normal(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||
pub struct FnHeader {
|
||||
pub safety: Safety,
|
||||
pub safety: HeaderSafety,
|
||||
pub constness: Constness,
|
||||
pub asyncness: IsAsync,
|
||||
pub abi: ExternAbi,
|
||||
|
@ -3780,7 +3801,18 @@ impl FnHeader {
|
|||
}
|
||||
|
||||
pub fn is_unsafe(&self) -> bool {
|
||||
self.safety.is_unsafe()
|
||||
self.safety().is_unsafe()
|
||||
}
|
||||
|
||||
pub fn is_safe(&self) -> bool {
|
||||
self.safety().is_safe()
|
||||
}
|
||||
|
||||
pub fn safety(&self) -> Safety {
|
||||
match self.safety {
|
||||
HeaderSafety::SafeTargetFeatures => Safety::Unsafe,
|
||||
HeaderSafety::Normal(safety) => safety,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1336,7 +1336,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
{
|
||||
icx.lowerer().lower_fn_ty(
|
||||
hir_id,
|
||||
sig.header.safety,
|
||||
sig.header.safety(),
|
||||
sig.header.abi,
|
||||
sig.decl,
|
||||
Some(generics),
|
||||
|
@ -1351,13 +1351,18 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
|
|||
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
|
||||
generics,
|
||||
..
|
||||
}) => {
|
||||
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
|
||||
}
|
||||
}) => icx.lowerer().lower_fn_ty(
|
||||
hir_id,
|
||||
header.safety(),
|
||||
header.abi,
|
||||
decl,
|
||||
Some(generics),
|
||||
None,
|
||||
),
|
||||
|
||||
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
|
||||
let abi = tcx.hir().get_foreign_abi(hir_id);
|
||||
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety)
|
||||
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety())
|
||||
}
|
||||
|
||||
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor().is_some() => {
|
||||
|
@ -1405,7 +1410,7 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
|
|||
|
||||
icx.lowerer().lower_fn_ty(
|
||||
icx.tcx().local_def_id_to_hir_id(def_id),
|
||||
sig.header.safety,
|
||||
sig.header.safety(),
|
||||
sig.header.abi,
|
||||
sig.decl,
|
||||
Some(generics),
|
||||
|
|
|
@ -2407,7 +2407,7 @@ impl<'a> State<'a> {
|
|||
self.print_fn(
|
||||
decl,
|
||||
hir::FnHeader {
|
||||
safety,
|
||||
safety: safety.into(),
|
||||
abi,
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
|
@ -2423,12 +2423,20 @@ impl<'a> State<'a> {
|
|||
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
|
||||
self.print_constness(header.constness);
|
||||
|
||||
let safety = match header.safety {
|
||||
hir::HeaderSafety::SafeTargetFeatures => {
|
||||
self.word_nbsp("#[target_feature]");
|
||||
hir::Safety::Safe
|
||||
}
|
||||
hir::HeaderSafety::Normal(safety) => safety,
|
||||
};
|
||||
|
||||
match header.asyncness {
|
||||
hir::IsAsync::NotAsync => {}
|
||||
hir::IsAsync::Async(_) => self.word_nbsp("async"),
|
||||
}
|
||||
|
||||
self.print_safety(header.safety);
|
||||
self.print_safety(safety);
|
||||
|
||||
if header.abi != ExternAbi::Rust {
|
||||
self.word_nbsp("extern");
|
||||
|
|
|
@ -932,10 +932,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
return Err(TypeError::ForceInlineCast);
|
||||
}
|
||||
|
||||
// Safe `#[target_feature]` functions are not assignable to safe fn pointers
|
||||
// (RFC 2396).
|
||||
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||
if matches!(fn_attrs.inline, InlineAttr::Force { .. }) {
|
||||
return Err(TypeError::ForceInlineCast);
|
||||
}
|
||||
|
||||
// FIXME(target_feature): Safe `#[target_feature]` functions could be cast to safe fn pointers (RFC 2396),
|
||||
// as you can already write that "cast" in user code by wrapping a target_feature fn call in a closure,
|
||||
// which is safe. This is sound because you already need to be executing code that is satisfying the target
|
||||
// feature constraints..
|
||||
if b_hdr.safety.is_safe()
|
||||
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
|
||||
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
|
||||
{
|
||||
return Err(TypeError::TargetFeatureCast(def_id));
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ fn typeck_with_fallback<'tcx>(
|
|||
// type that has an infer in it, lower the type directly so that it'll
|
||||
// be correctly filled with infer. We'll use this inference to provide
|
||||
// a suggestion later on.
|
||||
fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl, None, None)
|
||||
fcx.lowerer().lower_fn_ty(id, header.safety(), header.abi, decl, None, None)
|
||||
} else {
|
||||
tcx.fn_sig(def_id).instantiate_identity()
|
||||
};
|
||||
|
|
|
@ -30,6 +30,8 @@ pub struct CodegenFnAttrs {
|
|||
/// features (only enabled features are supported right now).
|
||||
/// Implied target features have already been applied.
|
||||
pub target_features: Vec<TargetFeature>,
|
||||
/// Whether the function was declared safe, but has target features
|
||||
pub safe_target_features: bool,
|
||||
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
||||
pub linkage: Option<Linkage>,
|
||||
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
|
||||
|
@ -150,6 +152,7 @@ impl CodegenFnAttrs {
|
|||
link_name: None,
|
||||
link_ordinal: None,
|
||||
target_features: vec![],
|
||||
safe_target_features: false,
|
||||
linkage: None,
|
||||
import_linkage: None,
|
||||
link_section: None,
|
||||
|
|
|
@ -222,6 +222,7 @@ pub struct DelegationFnSig {
|
|||
pub param_count: usize,
|
||||
pub has_self: bool,
|
||||
pub c_variadic: bool,
|
||||
pub target_feature: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
|
|
@ -690,7 +690,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
|||
if with_reduced_queries() {
|
||||
p!(print_def_path(def_id, args));
|
||||
} else {
|
||||
let sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
|
||||
let mut sig = self.tcx().fn_sig(def_id).instantiate(self.tcx(), args);
|
||||
if self.tcx().codegen_fn_attrs(def_id).safe_target_features {
|
||||
p!("#[target_features] ");
|
||||
sig = sig.map_bound(|mut sig| {
|
||||
sig.safety = hir::Safety::Safe;
|
||||
sig
|
||||
});
|
||||
}
|
||||
p!(print(sig), " {{", print_value_path(def_id, args), "}}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -478,19 +478,27 @@ 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() {
|
||||
let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
|
||||
let fn_ty = self.thir[fun].ty;
|
||||
let sig = fn_ty.fn_sig(self.tcx);
|
||||
let (callee_features, safe_target_features): (&[_], _) = match fn_ty.kind() {
|
||||
ty::FnDef(func_id, ..) => {
|
||||
let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
|
||||
(&cg_attrs.target_features, cg_attrs.safe_target_features)
|
||||
}
|
||||
_ => (&[], false),
|
||||
};
|
||||
if sig.safety().is_unsafe() && !safe_target_features {
|
||||
let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
|
||||
Some(*func_id)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
|
||||
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
|
||||
} else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
|
||||
// If the called function has target features the calling function hasn't,
|
||||
// the call requires `unsafe`. Don't check this on wasm
|
||||
// targets, though. For more information on wasm see the
|
||||
// is_like_wasm check in hir_analysis/src/collect.rs
|
||||
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
|
||||
if !self.tcx.sess.target.options.is_like_wasm
|
||||
&& !callee_features.iter().all(|feature| {
|
||||
self.body_target_features.iter().any(|f| f.name == feature.name)
|
||||
|
@ -739,7 +747,10 @@ impl UnsafeOpKind {
|
|||
) {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_owner = tcx.hir_owner_node(parent_id);
|
||||
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| sig.header.is_unsafe());
|
||||
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
|
||||
// Do not suggest for safe target_feature functions
|
||||
matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
|
||||
});
|
||||
let unsafe_not_inherited_note = if should_suggest {
|
||||
suggest_unsafe_block.then(|| {
|
||||
let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span;
|
||||
|
@ -902,7 +913,7 @@ impl UnsafeOpKind {
|
|||
{
|
||||
true
|
||||
} else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
|
||||
&& sig.header.is_unsafe()
|
||||
&& matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
|
||||
{
|
||||
true
|
||||
} else {
|
||||
|
@ -1111,7 +1122,16 @@ 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 }
|
||||
match fn_sig.header.safety {
|
||||
// We typeck the body as safe, but otherwise treat it as unsafe everywhere else.
|
||||
// Call sites to other SafeTargetFeatures functions are checked explicitly and don't need
|
||||
// to care about safety of the body.
|
||||
hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
|
||||
hir::HeaderSafety::Normal(safety) => match safety {
|
||||
hir::Safety::Unsafe => SafetyContext::UnsafeFn,
|
||||
hir::Safety::Safe => SafetyContext::Safe,
|
||||
},
|
||||
}
|
||||
});
|
||||
let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
|
||||
let mut warnings = Vec::new();
|
||||
|
|
|
@ -5019,12 +5019,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);
|
||||
}
|
||||
|
@ -5043,7 +5044,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);
|
||||
|
@ -5076,7 +5077,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);
|
||||
}
|
||||
|
|
|
@ -824,9 +824,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn cmp_fn_sig(
|
||||
&self,
|
||||
sig1: &ty::PolyFnSig<'tcx>,
|
||||
fn_def1: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
|
||||
fn_def1: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
|
||||
sig2: &ty::PolyFnSig<'tcx>,
|
||||
fn_def2: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
|
||||
fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
|
||||
) -> (DiagStyledString, DiagStyledString) {
|
||||
let sig1 = &(self.normalize_fn_sig)(*sig1);
|
||||
let sig2 = &(self.normalize_fn_sig)(*sig2);
|
||||
|
@ -850,8 +850,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
|
||||
// ^^^^^^
|
||||
values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
|
||||
values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
|
||||
let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
|
||||
None => sig.safety.prefix_str(),
|
||||
Some((did, _)) => {
|
||||
if self.tcx.codegen_fn_attrs(did).safe_target_features {
|
||||
"#[target_features] "
|
||||
} else {
|
||||
sig.safety.prefix_str()
|
||||
}
|
||||
}
|
||||
};
|
||||
let safety1 = safety(fn_def1, sig1);
|
||||
let safety2 = safety(fn_def2, sig2);
|
||||
values.0.push(safety1, safety1 != safety2);
|
||||
values.1.push(safety2, safety1 != safety2);
|
||||
|
||||
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
|
||||
// ^^^^^^^^^^
|
||||
|
@ -932,23 +944,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(values.1).0.extend(x2.0);
|
||||
}
|
||||
|
||||
let fmt = |(did, args)| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
|
||||
let fmt = |did, args| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
|
||||
|
||||
match (fn_def1, fn_def2) {
|
||||
(None, None) => {}
|
||||
(Some(fn_def1), Some(fn_def2)) => {
|
||||
let path1 = fmt(fn_def1);
|
||||
let path2 = fmt(fn_def2);
|
||||
(Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
|
||||
let path1 = fmt(fn_def1, fn_args1);
|
||||
let path2 = fmt(fn_def2, fn_args2);
|
||||
let same_path = path1 == path2;
|
||||
values.0.push(path1, !same_path);
|
||||
values.1.push(path2, !same_path);
|
||||
}
|
||||
(Some(fn_def1), None) => {
|
||||
values.0.push_highlighted(fmt(fn_def1));
|
||||
(Some((fn_def1, Some(fn_args1))), None) => {
|
||||
values.0.push_highlighted(fmt(fn_def1, fn_args1));
|
||||
}
|
||||
(None, Some(fn_def2)) => {
|
||||
values.1.push_highlighted(fmt(fn_def2));
|
||||
(None, Some((fn_def2, Some(fn_args2)))) => {
|
||||
values.1.push_highlighted(fmt(fn_def2, fn_args2));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
values
|
||||
|
@ -1339,17 +1351,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
|
||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig2, Some((*did2, args2)))
|
||||
self.cmp_fn_sig(
|
||||
&sig1,
|
||||
Some((*did1, Some(args1))),
|
||||
&sig2,
|
||||
Some((*did2, Some(args2))),
|
||||
)
|
||||
}
|
||||
|
||||
(ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
|
||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig_tys2.with(*hdr2), None)
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, Some(args1))), &sig_tys2.with(*hdr2), None)
|
||||
}
|
||||
|
||||
(ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
|
||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
|
||||
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, args2)))
|
||||
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, Some(args2))))
|
||||
}
|
||||
|
||||
(ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
|
||||
|
@ -1531,7 +1548,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(false, Mismatch::Fixed("existential projection"))
|
||||
}
|
||||
};
|
||||
let Some(vals) = self.values_str(values) else {
|
||||
let Some(vals) = self.values_str(values, cause) else {
|
||||
// Derived error. Cancel the emitter.
|
||||
// NOTE(eddyb) this was `.cancel()`, but `diag`
|
||||
// is borrowed, so we can't fully defuse it.
|
||||
|
@ -1956,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
})
|
||||
| ObligationCauseCode::BlockTailExpression(.., source)) = code
|
||||
&& let hir::MatchSource::TryDesugar(_) = source
|
||||
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values)
|
||||
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
|
||||
found: found_ty.content(),
|
||||
|
@ -2085,6 +2102,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn values_str(
|
||||
&self,
|
||||
values: ValuePairs<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
|
||||
match values {
|
||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
|
@ -2109,7 +2127,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if exp_found.references_error() {
|
||||
return None;
|
||||
}
|
||||
let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, None, &exp_found.found, None);
|
||||
let (fn_def1, fn_def2) = if let ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
..
|
||||
} = *cause.code()
|
||||
{
|
||||
(Some((trait_item_def_id, None)), Some((impl_item_def_id.to_def_id(), None)))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let (exp, fnd) =
|
||||
self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
|
||||
Some((exp, fnd, None))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -461,9 +461,11 @@ impl<T> Trait<T> for X {
|
|||
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
|
||||
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
|
||||
if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety {
|
||||
diag.note(
|
||||
if !tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||
diag.note(
|
||||
"unsafe functions cannot be coerced into safe function pointers",
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::Adt(_, _), ty::Adt(def, args))
|
||||
|
|
|
@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||
span: trace.cause.span,
|
||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
||||
expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
|
||||
expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
|
||||
}
|
||||
.add_to_diag(err),
|
||||
infer::Reborrow(span) => {
|
||||
|
@ -946,8 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
if let infer::Subtype(ref sup_trace) = sup_origin
|
||||
&& let infer::Subtype(ref sub_trace) = sub_origin
|
||||
&& let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
|
||||
&& let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
|
||||
&& let Some((sup_expected, sup_found, _)) =
|
||||
self.values_str(sup_trace.values, &sup_trace.cause)
|
||||
&& let Some((sub_expected, sub_found, _)) =
|
||||
self.values_str(sub_trace.values, &sup_trace.cause)
|
||||
&& sub_expected == sup_expected
|
||||
&& sub_found == sup_found
|
||||
{
|
||||
|
|
|
@ -205,9 +205,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
if self_ty.is_fn() {
|
||||
let fn_sig = self_ty.fn_sig(self.tcx);
|
||||
let shortname = match fn_sig.safety() {
|
||||
hir::Safety::Safe => "fn",
|
||||
hir::Safety::Unsafe => "unsafe fn",
|
||||
let shortname = if let ty::FnDef(def_id, _) = self_ty.kind()
|
||||
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
|
||||
{
|
||||
"#[target_feature] fn"
|
||||
} else {
|
||||
match fn_sig.safety() {
|
||||
hir::Safety::Safe => "fn",
|
||||
hir::Safety::Unsafe => "unsafe fn",
|
||||
}
|
||||
};
|
||||
flags.push((sym::_Self, Some(shortname.to_owned())));
|
||||
}
|
||||
|
|
|
@ -3094,7 +3094,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
|
|||
let kind = match item.kind {
|
||||
hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
|
||||
clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
|
||||
sig.header.safety,
|
||||
sig.header.safety(),
|
||||
),
|
||||
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
|
||||
Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None },
|
||||
|
|
|
@ -668,17 +668,28 @@ impl Item {
|
|||
ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
|
||||
ty::Asyncness::No => hir::IsAsync::NotAsync,
|
||||
};
|
||||
hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
|
||||
hir::FnHeader {
|
||||
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else {
|
||||
sig.safety().into()
|
||||
},
|
||||
abi: sig.abi(),
|
||||
constness,
|
||||
asyncness,
|
||||
}
|
||||
}
|
||||
let header = match self.kind {
|
||||
ItemKind::ForeignFunctionItem(_, safety) => {
|
||||
let def_id = self.def_id().unwrap();
|
||||
let abi = tcx.fn_sig(def_id).skip_binder().abi();
|
||||
hir::FnHeader {
|
||||
safety: if abi == ExternAbi::RustIntrinsic {
|
||||
intrinsic_operation_unsafety(tcx, def_id.expect_local())
|
||||
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||
hir::HeaderSafety::SafeTargetFeatures
|
||||
} else if abi == ExternAbi::RustIntrinsic {
|
||||
intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
|
||||
} else {
|
||||
safety
|
||||
safety.into()
|
||||
},
|
||||
abi,
|
||||
constness: if tcx.is_const_fn(def_id) {
|
||||
|
|
|
@ -1637,6 +1637,15 @@ impl PrintWithSpace for hir::Safety {
|
|||
}
|
||||
}
|
||||
|
||||
impl PrintWithSpace for hir::HeaderSafety {
|
||||
fn print_with_space(&self) -> &str {
|
||||
match self {
|
||||
hir::HeaderSafety::SafeTargetFeatures => "",
|
||||
hir::HeaderSafety::Normal(safety) => safety.print_with_space(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PrintWithSpace for hir::IsAsync {
|
||||
fn print_with_space(&self) -> &str {
|
||||
match self {
|
||||
|
|
|
@ -469,7 +469,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl
|
|||
|
||||
let unsafety_flag = match myitem.kind {
|
||||
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
|
||||
if myitem.fn_header(tcx).unwrap().safety.is_unsafe() =>
|
||||
if myitem.fn_header(tcx).unwrap().is_unsafe() =>
|
||||
{
|
||||
"<sup title=\"unsafe function\">⚠</sup>"
|
||||
}
|
||||
|
|
|
@ -419,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
|||
id: LocalDefId,
|
||||
) -> Self::Result {
|
||||
if let Some(header) = kind.header()
|
||||
&& header.safety.is_unsafe()
|
||||
&& header.is_unsafe()
|
||||
{
|
||||
ControlFlow::Break(())
|
||||
} else {
|
||||
|
|
|
@ -32,7 +32,7 @@ pub fn check(
|
|||
}
|
||||
|
||||
let span = cx.tcx.def_span(owner_id);
|
||||
match (headers.safety, sig.header.safety) {
|
||||
match (headers.safety, sig.header.safety()) {
|
||||
(false, Safety::Unsafe) => span_lint(
|
||||
cx,
|
||||
MISSING_SAFETY_DOC,
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
|||
ImplicitSelfKind::None => return,
|
||||
};
|
||||
|
||||
let name = if sig.header.safety.is_unsafe() {
|
||||
let name = if sig.header.is_unsafe() {
|
||||
name.strip_suffix("_unchecked").unwrap_or(name)
|
||||
} else {
|
||||
name
|
||||
|
|
|
@ -20,8 +20,8 @@ pub(super) fn check_fn<'tcx>(
|
|||
def_id: LocalDefId,
|
||||
) {
|
||||
let safety = match kind {
|
||||
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
|
||||
intravisit::FnKind::Method(_, sig) => sig.header.safety,
|
||||
intravisit::FnKind::ItemFn(_, _, header) => header.safety(),
|
||||
intravisit::FnKind::Method(_, sig) => sig.header.safety(),
|
||||
intravisit::FnKind::Closure => return,
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,7 @@ pub(super) fn check_fn<'tcx>(
|
|||
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
|
||||
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
|
||||
let body = cx.tcx.hir().body(eid);
|
||||
check_raw_ptr(cx, sig.header.safety, sig.decl, body, item.owner_id.def_id);
|
||||
check_raw_ptr(cx, sig.header.safety(), sig.decl, body, item.owner_id.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
|||
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
|
||||
// #11201
|
||||
&& let header = signature.header
|
||||
&& header.safety.is_safe()
|
||||
&& header.is_safe()
|
||||
&& header.abi == Abi::Rust
|
||||
&& impl_item.ident.name == sym::to_string
|
||||
&& let decl = signature.decl
|
||||
|
|
|
@ -5309,7 +5309,7 @@ fn lint_binary_expr_with_method_call(cx: &LateContext<'_>, info: &mut BinaryExpr
|
|||
}
|
||||
|
||||
const FN_HEADER: hir::FnHeader = hir::FnHeader {
|
||||
safety: hir::Safety::Safe,
|
||||
safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
|
||||
constness: hir::Constness::NotConst,
|
||||
asyncness: hir::IsAsync::NotAsync,
|
||||
abi: rustc_target::spec::abi::Abi::Rust,
|
||||
|
|
|
@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault {
|
|||
if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
|
||||
let name = impl_item.ident.name;
|
||||
let id = impl_item.owner_id;
|
||||
if sig.header.safety.is_unsafe() {
|
||||
if sig.header.is_unsafe() {
|
||||
// can't be implemented for unsafe new
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -541,7 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
|
|||
.collect();
|
||||
if let Some(args) = args
|
||||
&& !args.is_empty()
|
||||
&& body.is_none_or(|body| sig.header.safety.is_unsafe() || contains_unsafe_block(cx, body.value))
|
||||
&& body.is_none_or(|body| sig.header.is_unsafe() || contains_unsafe_block(cx, body.value))
|
||||
{
|
||||
span_lint_and_then(
|
||||
cx,
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
error[E0277]: the trait bound `fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}: AsyncFn()` is not satisfied
|
||||
error[E0277]: the trait bound `#[target_features] fn() -> Pin<Box<(dyn Future<Output = ()> + '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<Box<(dyn Future<Output = ()> + '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_features] fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> {target_feature}`
|
||||
note: required by a bound in `test`
|
||||
--> $DIR/fn-exception-target-features.rs:13:17
|
||||
|
|
||||
|
|
|
@ -3,8 +3,6 @@ fn main() {
|
|||
.map(
|
||||
#[target_feature(enable = "")]
|
||||
//~^ ERROR: attribute should be applied to a function
|
||||
//~| ERROR: feature named `` is not valid
|
||||
//~| NOTE: `` is not valid for this target
|
||||
#[track_caller]
|
||||
//~^ ERROR: `#[track_caller]` on closures is currently unstable
|
||||
//~| NOTE: see issue #87417
|
||||
|
|
|
@ -7,14 +7,8 @@ LL | #[target_feature(enable = "")]
|
|||
LL | |_| (),
|
||||
| ------ not a function definition
|
||||
|
||||
error: the feature named `` is not valid for this target
|
||||
--> $DIR/issue-68060.rs:4:30
|
||||
|
|
||||
LL | #[target_feature(enable = "")]
|
||||
| ^^^^^^^^^^^ `` is not valid for this target
|
||||
|
||||
error[E0658]: `#[track_caller]` on closures is currently unstable
|
||||
--> $DIR/issue-68060.rs:8:13
|
||||
--> $DIR/issue-68060.rs:6:13
|
||||
|
|
||||
LL | #[track_caller]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
@ -23,6 +17,6 @@ LL | #[track_caller]
|
|||
= help: add `#![feature(closure_track_caller)]` 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 3 previous errors
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
@ -10,13 +10,8 @@ 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_features] 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();
|
||||
| ~~~~~~~~~~~
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -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_features] fn() {foo}`
|
||||
call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `#[target_features] fn() {foo}`
|
||||
call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `#[target_features] fn() {foo}`
|
||||
|
||||
call(foo_unsafe);
|
||||
//~^ ERROR expected a `Fn()` closure, found `unsafe fn() {foo_unsafe}`
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
error[E0277]: expected a `Fn()` closure, found `fn() {foo}`
|
||||
error[E0277]: expected a `Fn()` closure, found `#[target_features] fn() {foo}`
|
||||
--> $DIR/fn-traits.rs:24:10
|
||||
|
|
||||
LL | call(foo);
|
||||
| ---- ^^^ expected an `Fn()` closure, found `fn() {foo}`
|
||||
| ---- ^^^ expected an `Fn()` closure, found `#[target_features] fn() {foo}`
|
||||
| |
|
||||
| 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_features] fn() {foo}`
|
||||
= note: wrap the `#[target_features] 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 +15,16 @@ 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_features] fn() {foo}`
|
||||
--> $DIR/fn-traits.rs:25:14
|
||||
|
|
||||
LL | call_mut(foo);
|
||||
| -------- ^^^ expected an `FnMut()` closure, found `fn() {foo}`
|
||||
| -------- ^^^ expected an `FnMut()` closure, found `#[target_features] fn() {foo}`
|
||||
| |
|
||||
| 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_features] fn() {foo}`
|
||||
= note: wrap the `#[target_features] 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 +32,16 @@ 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_features] fn() {foo}`
|
||||
--> $DIR/fn-traits.rs:26:15
|
||||
|
|
||||
LL | call_once(foo);
|
||||
| --------- ^^^ expected an `FnOnce()` closure, found `fn() {foo}`
|
||||
| --------- ^^^ expected an `FnOnce()` closure, found `#[target_features] fn() {foo}`
|
||||
| |
|
||||
| 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_features] fn() {foo}`
|
||||
= note: wrap the `#[target_features] 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
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -7,8 +7,22 @@ LL |
|
|||
LL | fn foo(&self) {}
|
||||
| ------------- not an `unsafe` function
|
||||
|
||||
error[E0053]: method `foo` has an incompatible type for trait
|
||||
--> $DIR/trait-impl.rs:15:5
|
||||
|
|
||||
LL | fn foo(&self) {}
|
||||
| ^^^^^^^^^^^^^ expected safe fn, found unsafe fn
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/trait-impl.rs:6:5
|
||||
|
|
||||
LL | fn foo(&self);
|
||||
| ^^^^^^^^^^^^^^
|
||||
= note: expected signature `fn(&Bar)`
|
||||
found signature `#[target_features] fn(&Bar)`
|
||||
|
||||
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`.
|
||||
|
|
|
@ -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 unsafe fn
|
||||
//~| NOTE: expected signature `fn()`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
@ -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")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
@ -193,7 +193,7 @@ LL | fn foo();
|
|||
| --------- `foo` from trait
|
||||
|
||||
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 +205,21 @@ 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[E0053]: method `foo` has an incompatible type for trait
|
||||
--> $DIR/invalid-attribute.rs:108:5
|
||||
|
|
||||
LL | fn foo() {}
|
||||
| ^^^^^^^^ expected safe fn, found unsafe fn
|
||||
|
|
||||
note: type in trait
|
||||
--> $DIR/invalid-attribute.rs:99:5
|
||||
|
|
||||
LL | fn foo();
|
||||
| ^^^^^^^^^
|
||||
= note: expected signature `fn()`
|
||||
found signature `#[target_features] fn()`
|
||||
|
||||
Some errors have detailed explanations: E0046, E0658.
|
||||
error: aborting due to 24 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0046, E0053, E0658.
|
||||
For more information about an error, try `rustc --explain E0046`.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue