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> {
|
) -> hir::FnSig<'hir> {
|
||||||
let header = if let Some(local_sig_id) = sig_id.as_local() {
|
let header = if let Some(local_sig_id) = sig_id.as_local() {
|
||||||
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
|
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(),
|
None => self.generate_header_error(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -198,7 +205,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
Asyncness::No => hir::IsAsync::NotAsync,
|
Asyncness::No => hir::IsAsync::NotAsync,
|
||||||
};
|
};
|
||||||
hir::FnHeader {
|
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),
|
constness: self.tcx.constness(sig_id),
|
||||||
asyncness,
|
asyncness,
|
||||||
abi: sig.abi,
|
abi: sig.abi,
|
||||||
|
@ -384,7 +395,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
fn generate_header_error(&self) -> hir::FnHeader {
|
fn generate_header_error(&self) -> hir::FnHeader {
|
||||||
hir::FnHeader {
|
hir::FnHeader {
|
||||||
safety: hir::Safety::Safe,
|
safety: hir::Safety::Safe.into(),
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
asyncness: hir::IsAsync::NotAsync,
|
asyncness: hir::IsAsync::NotAsync,
|
||||||
abi: abi::Abi::Rust,
|
abi: abi::Abi::Rust,
|
||||||
|
|
|
@ -231,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
});
|
});
|
||||||
let sig = hir::FnSig {
|
let sig = hir::FnSig {
|
||||||
decl,
|
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),
|
span: this.lower_span(*fn_sig_span),
|
||||||
};
|
};
|
||||||
hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() }
|
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> {
|
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 hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
let owner_id = hir_id.expect_owner();
|
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 {
|
let item = hir::ForeignItem {
|
||||||
owner_id,
|
owner_id,
|
||||||
ident: self.lower_ident(i.ident),
|
ident: self.lower_ident(i.ident),
|
||||||
|
@ -634,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Unmarked safety in unsafe block defaults to unsafe.
|
// 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::ForeignItemKind::Fn(
|
||||||
hir::FnSig { header, decl, span: self.lower_span(sig.span) },
|
hir::FnSig { header, decl, span: self.lower_span(sig.span) },
|
||||||
|
@ -776,6 +776,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
i.id,
|
i.id,
|
||||||
FnDeclKind::Trait,
|
FnDeclKind::Trait,
|
||||||
sig.header.coroutine_kind,
|
sig.header.coroutine_kind,
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false)
|
||||||
}
|
}
|
||||||
|
@ -795,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
i.id,
|
i.id,
|
||||||
FnDeclKind::Trait,
|
FnDeclKind::Trait,
|
||||||
sig.header.coroutine_kind,
|
sig.header.coroutine_kind,
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
|
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true)
|
||||||
}
|
}
|
||||||
|
@ -911,6 +913,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
i.id,
|
i.id,
|
||||||
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
if self.is_in_trait_impl { FnDeclKind::Impl } else { FnDeclKind::Inherent },
|
||||||
sig.header.coroutine_kind,
|
sig.header.coroutine_kind,
|
||||||
|
attrs,
|
||||||
);
|
);
|
||||||
|
|
||||||
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
(generics, hir::ImplItemKind::Fn(sig, body_id))
|
||||||
|
@ -1339,8 +1342,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
kind: FnDeclKind,
|
kind: FnDeclKind,
|
||||||
coroutine_kind: Option<CoroutineKind>,
|
coroutine_kind: Option<CoroutineKind>,
|
||||||
|
attrs: &[hir::Attribute],
|
||||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
) -> (&'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 itctx = ImplTraitContext::Universal;
|
||||||
let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
|
let (generics, decl) = self.lower_generics(generics, id, itctx, |this| {
|
||||||
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
|
||||||
|
@ -1352,14 +1356,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
h: FnHeader,
|
h: FnHeader,
|
||||||
default_safety: hir::Safety,
|
default_safety: hir::Safety,
|
||||||
|
attrs: &[hir::Attribute],
|
||||||
) -> hir::FnHeader {
|
) -> hir::FnHeader {
|
||||||
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
|
let asyncness = if let Some(CoroutineKind::Async { span, .. }) = h.coroutine_kind {
|
||||||
hir::IsAsync::Async(span)
|
hir::IsAsync::Async(span)
|
||||||
} else {
|
} else {
|
||||||
hir::IsAsync::NotAsync
|
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 {
|
hir::FnHeader {
|
||||||
safety: self.lower_safety(h.safety, default_safety),
|
safety,
|
||||||
asyncness,
|
asyncness,
|
||||||
constness: self.lower_constness(h.constness),
|
constness: self.lower_constness(h.constness),
|
||||||
abi: self.lower_extern(h.ext),
|
abi: self.lower_extern(h.ext),
|
||||||
|
|
|
@ -250,10 +250,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sym::target_feature => {
|
sym::target_feature => {
|
||||||
if !tcx.is_closure_like(did.to_def_id())
|
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||||
&& let Some(fn_sig) = fn_sig()
|
tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn");
|
||||||
&& fn_sig.skip_binder().safety().is_safe()
|
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 {
|
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
|
||||||
// The `#[target_feature]` attribute is allowed on
|
// The `#[target_feature]` attribute is allowed on
|
||||||
// WebAssembly targets on all functions, including safe
|
// 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)]
|
#[derive(Copy, Clone, Debug, HashStable_Generic)]
|
||||||
pub struct FnHeader {
|
pub struct FnHeader {
|
||||||
pub safety: Safety,
|
pub safety: HeaderSafety,
|
||||||
pub constness: Constness,
|
pub constness: Constness,
|
||||||
pub asyncness: IsAsync,
|
pub asyncness: IsAsync,
|
||||||
pub abi: ExternAbi,
|
pub abi: ExternAbi,
|
||||||
|
@ -3780,7 +3801,18 @@ impl FnHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_unsafe(&self) -> bool {
|
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(
|
icx.lowerer().lower_fn_ty(
|
||||||
hir_id,
|
hir_id,
|
||||||
sig.header.safety,
|
sig.header.safety(),
|
||||||
sig.header.abi,
|
sig.header.abi,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
Some(generics),
|
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: _ }, _),
|
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
|
||||||
generics,
|
generics,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => icx.lowerer().lower_fn_ty(
|
||||||
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
|
hir_id,
|
||||||
}
|
header.safety(),
|
||||||
|
header.abi,
|
||||||
|
decl,
|
||||||
|
Some(generics),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
|
||||||
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
|
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => {
|
||||||
let abi = tcx.hir().get_foreign_abi(hir_id);
|
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() => {
|
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.lowerer().lower_fn_ty(
|
||||||
icx.tcx().local_def_id_to_hir_id(def_id),
|
icx.tcx().local_def_id_to_hir_id(def_id),
|
||||||
sig.header.safety,
|
sig.header.safety(),
|
||||||
sig.header.abi,
|
sig.header.abi,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
Some(generics),
|
Some(generics),
|
||||||
|
|
|
@ -2407,7 +2407,7 @@ impl<'a> State<'a> {
|
||||||
self.print_fn(
|
self.print_fn(
|
||||||
decl,
|
decl,
|
||||||
hir::FnHeader {
|
hir::FnHeader {
|
||||||
safety,
|
safety: safety.into(),
|
||||||
abi,
|
abi,
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
asyncness: hir::IsAsync::NotAsync,
|
asyncness: hir::IsAsync::NotAsync,
|
||||||
|
@ -2423,12 +2423,20 @@ impl<'a> State<'a> {
|
||||||
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
|
fn print_fn_header_info(&mut self, header: hir::FnHeader) {
|
||||||
self.print_constness(header.constness);
|
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 {
|
match header.asyncness {
|
||||||
hir::IsAsync::NotAsync => {}
|
hir::IsAsync::NotAsync => {}
|
||||||
hir::IsAsync::Async(_) => self.word_nbsp("async"),
|
hir::IsAsync::Async(_) => self.word_nbsp("async"),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.print_safety(header.safety);
|
self.print_safety(safety);
|
||||||
|
|
||||||
if header.abi != ExternAbi::Rust {
|
if header.abi != ExternAbi::Rust {
|
||||||
self.word_nbsp("extern");
|
self.word_nbsp("extern");
|
||||||
|
|
|
@ -932,10 +932,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||||
return Err(TypeError::ForceInlineCast);
|
return Err(TypeError::ForceInlineCast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safe `#[target_feature]` functions are not assignable to safe fn pointers
|
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
|
||||||
// (RFC 2396).
|
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()
|
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));
|
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
|
// 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
|
// be correctly filled with infer. We'll use this inference to provide
|
||||||
// a suggestion later on.
|
// 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 {
|
} else {
|
||||||
tcx.fn_sig(def_id).instantiate_identity()
|
tcx.fn_sig(def_id).instantiate_identity()
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,8 @@ pub struct CodegenFnAttrs {
|
||||||
/// features (only enabled features are supported right now).
|
/// features (only enabled features are supported right now).
|
||||||
/// Implied target features have already been applied.
|
/// Implied target features have already been applied.
|
||||||
pub target_features: Vec<TargetFeature>,
|
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.
|
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
|
||||||
pub linkage: Option<Linkage>,
|
pub linkage: Option<Linkage>,
|
||||||
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
|
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
|
||||||
|
@ -150,6 +152,7 @@ impl CodegenFnAttrs {
|
||||||
link_name: None,
|
link_name: None,
|
||||||
link_ordinal: None,
|
link_ordinal: None,
|
||||||
target_features: vec![],
|
target_features: vec![],
|
||||||
|
safe_target_features: false,
|
||||||
linkage: None,
|
linkage: None,
|
||||||
import_linkage: None,
|
import_linkage: None,
|
||||||
link_section: None,
|
link_section: None,
|
||||||
|
|
|
@ -222,6 +222,7 @@ pub struct DelegationFnSig {
|
||||||
pub param_count: usize,
|
pub param_count: usize,
|
||||||
pub has_self: bool,
|
pub has_self: bool,
|
||||||
pub c_variadic: bool,
|
pub c_variadic: bool,
|
||||||
|
pub target_feature: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
|
|
@ -690,7 +690,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
|
||||||
if with_reduced_queries() {
|
if with_reduced_queries() {
|
||||||
p!(print_def_path(def_id, args));
|
p!(print_def_path(def_id, args));
|
||||||
} else {
|
} 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), "}}");
|
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
|
return; // don't visit the whole expression
|
||||||
}
|
}
|
||||||
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
|
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
|
||||||
if self.thir[fun].ty.fn_sig(self.tcx).safety().is_unsafe() {
|
let fn_ty = self.thir[fun].ty;
|
||||||
let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
|
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)
|
Some(*func_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
|
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,
|
// If the called function has target features the calling function hasn't,
|
||||||
// the call requires `unsafe`. Don't check this on wasm
|
// the call requires `unsafe`. Don't check this on wasm
|
||||||
// targets, though. For more information on wasm see the
|
// targets, though. For more information on wasm see the
|
||||||
// is_like_wasm check in hir_analysis/src/collect.rs
|
// 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
|
if !self.tcx.sess.target.options.is_like_wasm
|
||||||
&& !callee_features.iter().all(|feature| {
|
&& !callee_features.iter().all(|feature| {
|
||||||
self.body_target_features.iter().any(|f| f.name == feature.name)
|
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_id = tcx.hir().get_parent_item(hir_id);
|
||||||
let parent_owner = tcx.hir_owner_node(parent_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 {
|
let unsafe_not_inherited_note = if should_suggest {
|
||||||
suggest_unsafe_block.then(|| {
|
suggest_unsafe_block.then(|| {
|
||||||
let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span;
|
let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span;
|
||||||
|
@ -902,7 +913,7 @@ impl UnsafeOpKind {
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
} else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
|
} 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
|
true
|
||||||
} else {
|
} 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 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| {
|
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 body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
|
||||||
let mut warnings = Vec::new();
|
let mut warnings = Vec::new();
|
||||||
|
|
|
@ -5019,12 +5019,13 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemInfoCollector<'_, '_, '_> {
|
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 {
|
let sig = DelegationFnSig {
|
||||||
header: sig.header,
|
header: sig.header,
|
||||||
param_count: sig.decl.inputs.len(),
|
param_count: sig.decl.inputs.len(),
|
||||||
has_self: sig.decl.has_self(),
|
has_self: sig.decl.has_self(),
|
||||||
c_variadic: sig.decl.c_variadic(),
|
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);
|
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::Trait(box Trait { ref generics, .. })
|
||||||
| ItemKind::TraitAlias(ref generics, _) => {
|
| ItemKind::TraitAlias(ref generics, _) => {
|
||||||
if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
|
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);
|
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) {
|
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
|
||||||
if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind {
|
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);
|
visit::walk_assoc_item(self, item, ctxt);
|
||||||
}
|
}
|
||||||
|
|
|
@ -824,9 +824,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
fn cmp_fn_sig(
|
fn cmp_fn_sig(
|
||||||
&self,
|
&self,
|
||||||
sig1: &ty::PolyFnSig<'tcx>,
|
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>,
|
sig2: &ty::PolyFnSig<'tcx>,
|
||||||
fn_def2: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
|
fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
|
||||||
) -> (DiagStyledString, DiagStyledString) {
|
) -> (DiagStyledString, DiagStyledString) {
|
||||||
let sig1 = &(self.normalize_fn_sig)(*sig1);
|
let sig1 = &(self.normalize_fn_sig)(*sig1);
|
||||||
let sig2 = &(self.normalize_fn_sig)(*sig2);
|
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
|
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
|
||||||
// ^^^^^^
|
// ^^^^^^
|
||||||
values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
|
let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
|
||||||
values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
|
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
|
// 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);
|
(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) {
|
match (fn_def1, fn_def2) {
|
||||||
(None, None) => {}
|
(Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
|
||||||
(Some(fn_def1), Some(fn_def2)) => {
|
let path1 = fmt(fn_def1, fn_args1);
|
||||||
let path1 = fmt(fn_def1);
|
let path2 = fmt(fn_def2, fn_args2);
|
||||||
let path2 = fmt(fn_def2);
|
|
||||||
let same_path = path1 == path2;
|
let same_path = path1 == path2;
|
||||||
values.0.push(path1, !same_path);
|
values.0.push(path1, !same_path);
|
||||||
values.1.push(path2, !same_path);
|
values.1.push(path2, !same_path);
|
||||||
}
|
}
|
||||||
(Some(fn_def1), None) => {
|
(Some((fn_def1, Some(fn_args1))), None) => {
|
||||||
values.0.push_highlighted(fmt(fn_def1));
|
values.0.push_highlighted(fmt(fn_def1, fn_args1));
|
||||||
}
|
}
|
||||||
(None, Some(fn_def2)) => {
|
(None, Some((fn_def2, Some(fn_args2)))) => {
|
||||||
values.1.push_highlighted(fmt(fn_def2));
|
values.1.push_highlighted(fmt(fn_def2, fn_args2));
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
values
|
values
|
||||||
|
@ -1339,17 +1351,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
|
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
|
||||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
||||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
|
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)) => {
|
(ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
|
||||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
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)) => {
|
(ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
|
||||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, 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)) => {
|
(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"))
|
(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.
|
// Derived error. Cancel the emitter.
|
||||||
// NOTE(eddyb) this was `.cancel()`, but `diag`
|
// NOTE(eddyb) this was `.cancel()`, but `diag`
|
||||||
// is borrowed, so we can't fully defuse it.
|
// is borrowed, so we can't fully defuse it.
|
||||||
|
@ -1956,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
| ObligationCauseCode::BlockTailExpression(.., source)) = code
|
| ObligationCauseCode::BlockTailExpression(.., source)) = code
|
||||||
&& let hir::MatchSource::TryDesugar(_) = source
|
&& 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 {
|
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
|
||||||
found: found_ty.content(),
|
found: found_ty.content(),
|
||||||
|
@ -2085,6 +2102,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
fn values_str(
|
fn values_str(
|
||||||
&self,
|
&self,
|
||||||
values: ValuePairs<'tcx>,
|
values: ValuePairs<'tcx>,
|
||||||
|
cause: &ObligationCause<'tcx>,
|
||||||
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
|
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
|
||||||
match values {
|
match values {
|
||||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
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() {
|
if exp_found.references_error() {
|
||||||
return None;
|
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))
|
Some((exp, fnd, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -461,9 +461,11 @@ impl<T> Trait<T> for X {
|
||||||
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
|
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
|
||||||
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
|
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
|
||||||
if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety {
|
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",
|
"unsafe functions cannot be coerced into safe function pointers",
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::Adt(_, _), ty::Adt(def, args))
|
(ty::Adt(_, _), ty::Adt(def, args))
|
||||||
|
|
|
@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||||
span: trace.cause.span,
|
span: trace.cause.span,
|
||||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
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),
|
.add_to_diag(err),
|
||||||
infer::Reborrow(span) => {
|
infer::Reborrow(span) => {
|
||||||
|
@ -946,8 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
if let infer::Subtype(ref sup_trace) = sup_origin
|
if let infer::Subtype(ref sup_trace) = sup_origin
|
||||||
&& let infer::Subtype(ref sub_trace) = sub_origin
|
&& let infer::Subtype(ref sub_trace) = sub_origin
|
||||||
&& let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
|
&& let Some((sup_expected, sup_found, _)) =
|
||||||
&& let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
|
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_expected == sup_expected
|
||||||
&& sub_found == sup_found
|
&& sub_found == sup_found
|
||||||
{
|
{
|
||||||
|
|
|
@ -205,9 +205,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||||
|
|
||||||
if self_ty.is_fn() {
|
if self_ty.is_fn() {
|
||||||
let fn_sig = self_ty.fn_sig(self.tcx);
|
let fn_sig = self_ty.fn_sig(self.tcx);
|
||||||
let shortname = match fn_sig.safety() {
|
let shortname = if let ty::FnDef(def_id, _) = self_ty.kind()
|
||||||
hir::Safety::Safe => "fn",
|
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
|
||||||
hir::Safety::Unsafe => "unsafe fn",
|
{
|
||||||
|
"#[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())));
|
flags.push((sym::_Self, Some(shortname.to_owned())));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3094,7 +3094,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
|
||||||
let kind = match item.kind {
|
let kind = match item.kind {
|
||||||
hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
|
hir::ForeignItemKind::Fn(sig, names, generics) => ForeignFunctionItem(
|
||||||
clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
|
clean_function(cx, &sig, generics, FunctionArgs::Names(names)),
|
||||||
sig.header.safety,
|
sig.header.safety(),
|
||||||
),
|
),
|
||||||
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
|
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
|
||||||
Static { type_: Box::new(clean_ty(ty, cx)), mutability, expr: None },
|
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::Yes => hir::IsAsync::Async(DUMMY_SP),
|
||||||
ty::Asyncness::No => hir::IsAsync::NotAsync,
|
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 {
|
let header = match self.kind {
|
||||||
ItemKind::ForeignFunctionItem(_, safety) => {
|
ItemKind::ForeignFunctionItem(_, safety) => {
|
||||||
let def_id = self.def_id().unwrap();
|
let def_id = self.def_id().unwrap();
|
||||||
let abi = tcx.fn_sig(def_id).skip_binder().abi();
|
let abi = tcx.fn_sig(def_id).skip_binder().abi();
|
||||||
hir::FnHeader {
|
hir::FnHeader {
|
||||||
safety: if abi == ExternAbi::RustIntrinsic {
|
safety: if tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||||
intrinsic_operation_unsafety(tcx, def_id.expect_local())
|
hir::HeaderSafety::SafeTargetFeatures
|
||||||
|
} else if abi == ExternAbi::RustIntrinsic {
|
||||||
|
intrinsic_operation_unsafety(tcx, def_id.expect_local()).into()
|
||||||
} else {
|
} else {
|
||||||
safety
|
safety.into()
|
||||||
},
|
},
|
||||||
abi,
|
abi,
|
||||||
constness: if tcx.is_const_fn(def_id) {
|
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 {
|
impl PrintWithSpace for hir::IsAsync {
|
||||||
fn print_with_space(&self) -> &str {
|
fn print_with_space(&self) -> &str {
|
||||||
match self {
|
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 {
|
let unsafety_flag = match myitem.kind {
|
||||||
clean::FunctionItem(_) | clean::ForeignFunctionItem(..)
|
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>"
|
"<sup title=\"unsafe function\">⚠</sup>"
|
||||||
}
|
}
|
||||||
|
|
|
@ -419,7 +419,7 @@ impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
|
||||||
id: LocalDefId,
|
id: LocalDefId,
|
||||||
) -> Self::Result {
|
) -> Self::Result {
|
||||||
if let Some(header) = kind.header()
|
if let Some(header) = kind.header()
|
||||||
&& header.safety.is_unsafe()
|
&& header.is_unsafe()
|
||||||
{
|
{
|
||||||
ControlFlow::Break(())
|
ControlFlow::Break(())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -32,7 +32,7 @@ pub fn check(
|
||||||
}
|
}
|
||||||
|
|
||||||
let span = cx.tcx.def_span(owner_id);
|
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(
|
(false, Safety::Unsafe) => span_lint(
|
||||||
cx,
|
cx,
|
||||||
MISSING_SAFETY_DOC,
|
MISSING_SAFETY_DOC,
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
|
||||||
ImplicitSelfKind::None => return,
|
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)
|
name.strip_suffix("_unchecked").unwrap_or(name)
|
||||||
} else {
|
} else {
|
||||||
name
|
name
|
||||||
|
|
|
@ -20,8 +20,8 @@ pub(super) fn check_fn<'tcx>(
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
) {
|
) {
|
||||||
let safety = match kind {
|
let safety = match kind {
|
||||||
intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
|
intravisit::FnKind::ItemFn(_, _, header) => header.safety(),
|
||||||
intravisit::FnKind::Method(_, sig) => sig.header.safety,
|
intravisit::FnKind::Method(_, sig) => sig.header.safety(),
|
||||||
intravisit::FnKind::Closure => return,
|
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<'_>) {
|
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 {
|
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
|
||||||
let body = cx.tcx.hir().body(eid);
|
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
|
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
|
||||||
// #11201
|
// #11201
|
||||||
&& let header = signature.header
|
&& let header = signature.header
|
||||||
&& header.safety.is_safe()
|
&& header.is_safe()
|
||||||
&& header.abi == Abi::Rust
|
&& header.abi == Abi::Rust
|
||||||
&& impl_item.ident.name == sym::to_string
|
&& impl_item.ident.name == sym::to_string
|
||||||
&& let decl = signature.decl
|
&& 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 {
|
const FN_HEADER: hir::FnHeader = hir::FnHeader {
|
||||||
safety: hir::Safety::Safe,
|
safety: hir::HeaderSafety::Normal(hir::Safety::Safe),
|
||||||
constness: hir::Constness::NotConst,
|
constness: hir::Constness::NotConst,
|
||||||
asyncness: hir::IsAsync::NotAsync,
|
asyncness: hir::IsAsync::NotAsync,
|
||||||
abi: rustc_target::spec::abi::Abi::Rust,
|
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 {
|
if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
|
||||||
let name = impl_item.ident.name;
|
let name = impl_item.ident.name;
|
||||||
let id = impl_item.owner_id;
|
let id = impl_item.owner_id;
|
||||||
if sig.header.safety.is_unsafe() {
|
if sig.header.is_unsafe() {
|
||||||
// can't be implemented for unsafe new
|
// can't be implemented for unsafe new
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -541,7 +541,7 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(args) = args
|
if let Some(args) = args
|
||||||
&& !args.is_empty()
|
&& !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(
|
span_lint_and_then(
|
||||||
cx,
|
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
|
--> $DIR/fn-exception-target-features.rs:16:10
|
||||||
|
|
|
|
||||||
LL | test(target_feature);
|
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
|
| 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`
|
note: required by a bound in `test`
|
||||||
--> $DIR/fn-exception-target-features.rs:13:17
|
--> $DIR/fn-exception-target-features.rs:13:17
|
||||||
|
|
|
|
||||||
|
|
|
@ -3,8 +3,6 @@ fn main() {
|
||||||
.map(
|
.map(
|
||||||
#[target_feature(enable = "")]
|
#[target_feature(enable = "")]
|
||||||
//~^ ERROR: attribute should be applied to a function
|
//~^ ERROR: attribute should be applied to a function
|
||||||
//~| ERROR: feature named `` is not valid
|
|
||||||
//~| NOTE: `` is not valid for this target
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
//~^ ERROR: `#[track_caller]` on closures is currently unstable
|
//~^ ERROR: `#[track_caller]` on closures is currently unstable
|
||||||
//~| NOTE: see issue #87417
|
//~| NOTE: see issue #87417
|
||||||
|
|
|
@ -7,14 +7,8 @@ LL | #[target_feature(enable = "")]
|
||||||
LL | |_| (),
|
LL | |_| (),
|
||||||
| ------ not a function definition
|
| ------ 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
|
error[E0658]: `#[track_caller]` on closures is currently unstable
|
||||||
--> $DIR/issue-68060.rs:8:13
|
--> $DIR/issue-68060.rs:6:13
|
||||||
|
|
|
|
||||||
LL | #[track_caller]
|
LL | #[track_caller]
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^
|
||||||
|
@ -23,6 +17,6 @@ LL | #[track_caller]
|
||||||
= help: add `#![feature(closure_track_caller)]` to the crate attributes to enable
|
= 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
|
= 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`.
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
|
@ -10,13 +10,8 @@ LL | let foo: fn() = foo;
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `fn()`
|
= note: expected fn pointer `fn()`
|
||||||
found fn item `fn() {foo}`
|
found fn item `#[target_features] fn() {foo}`
|
||||||
= note: fn items are distinct from fn pointers
|
|
||||||
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
|
= 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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,9 @@ fn call_once(f: impl FnOnce()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
call(foo); //~ ERROR expected a `Fn()` 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 `fn() {foo}`
|
call_mut(foo); //~ ERROR expected a `FnMut()` closure, found `#[target_features] fn() {foo}`
|
||||||
call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `fn() {foo}`
|
call_once(foo); //~ ERROR expected a `FnOnce()` closure, found `#[target_features] fn() {foo}`
|
||||||
|
|
||||||
call(foo_unsafe);
|
call(foo_unsafe);
|
||||||
//~^ ERROR expected a `Fn()` closure, found `unsafe fn() {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
|
--> $DIR/fn-traits.rs:24:10
|
||||||
|
|
|
|
||||||
LL | call(foo);
|
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
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `Fn()` is not implemented for fn item `fn() {foo}`
|
= help: the trait `Fn()` is not implemented for fn item `#[target_features] fn() {foo}`
|
||||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
= 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: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call`
|
note: required by a bound in `call`
|
||||||
--> $DIR/fn-traits.rs:11:17
|
--> $DIR/fn-traits.rs:11:17
|
||||||
|
@ -15,16 +15,16 @@ note: required by a bound in `call`
|
||||||
LL | fn call(f: impl Fn()) {
|
LL | fn call(f: impl Fn()) {
|
||||||
| ^^^^ required by this bound in `call`
|
| ^^^^ 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
|
--> $DIR/fn-traits.rs:25:14
|
||||||
|
|
|
|
||||||
LL | call_mut(foo);
|
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
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `FnMut()` is not implemented for fn item `fn() {foo}`
|
= help: the trait `FnMut()` is not implemented for fn item `#[target_features] fn() {foo}`
|
||||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
= 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: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call_mut`
|
note: required by a bound in `call_mut`
|
||||||
--> $DIR/fn-traits.rs:15:25
|
--> $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()) {
|
LL | fn call_mut(mut f: impl FnMut()) {
|
||||||
| ^^^^^^^ required by this bound in `call_mut`
|
| ^^^^^^^ 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
|
--> $DIR/fn-traits.rs:26:15
|
||||||
|
|
|
|
||||||
LL | call_once(foo);
|
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
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the trait `FnOnce()` is not implemented for fn item `fn() {foo}`
|
= help: the trait `FnOnce()` is not implemented for fn item `#[target_features] fn() {foo}`
|
||||||
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }`
|
= 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: `#[target_feature]` functions do not implement the `Fn` traits
|
||||||
note: required by a bound in `call_once`
|
note: required by a bound in `call_once`
|
||||||
--> $DIR/fn-traits.rs:19:22
|
--> $DIR/fn-traits.rs:19:22
|
||||||
|
|
|
@ -13,6 +13,7 @@ impl Foo for Bar {
|
||||||
#[target_feature(enable = "sse2")]
|
#[target_feature(enable = "sse2")]
|
||||||
//~^ ERROR cannot be applied to safe trait method
|
//~^ ERROR cannot be applied to safe trait method
|
||||||
fn foo(&self) {}
|
fn foo(&self) {}
|
||||||
|
//~^ ERROR method `foo` has an incompatible type for trait
|
||||||
|
|
||||||
#[target_feature(enable = "sse2")]
|
#[target_feature(enable = "sse2")]
|
||||||
unsafe fn unsf_foo(&self) {}
|
unsafe fn unsf_foo(&self) {}
|
||||||
|
|
|
@ -7,8 +7,22 @@ LL |
|
||||||
LL | fn foo(&self) {}
|
LL | fn foo(&self) {}
|
||||||
| ------------- not an `unsafe` function
|
| ------------- 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
|
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")]
|
LL | #[target_feature(enable = "sse2")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method
|
||||||
|
@ -16,5 +30,6 @@ LL |
|
||||||
LL | fn foo(&self) {}
|
LL | fn foo(&self) {}
|
||||||
| ------------- not an `unsafe` function
|
| ------------- 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 {
|
trait Quux {
|
||||||
fn foo(); //~ NOTE `foo` from trait
|
fn foo(); //~ NOTE `foo` from trait
|
||||||
|
//~^ NOTE: type in trait
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Quux for Foo {
|
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
|
//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
fn foo() {}
|
fn foo() {}
|
||||||
//~^ NOTE not an `unsafe` function
|
//~^ NOTE not an `unsafe` function
|
||||||
|
//~| ERROR: incompatible type for trait
|
||||||
|
//~| NOTE: expected safe fn, found unsafe fn
|
||||||
|
//~| NOTE: expected signature `fn()`
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -126,7 +126,7 @@ LL | impl Foo {}
|
||||||
| ----------- not a function definition
|
| ----------- not a function definition
|
||||||
|
|
||||||
error: attribute should be applied to 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")]
|
LL | #[target_feature(enable = "sse2")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -138,7 +138,7 @@ LL | | }
|
||||||
| |_____- not a function definition
|
| |_____- not a function definition
|
||||||
|
|
||||||
error: attribute should be applied to 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")]
|
LL | #[target_feature(enable = "sse2")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -193,7 +193,7 @@ LL | fn foo();
|
||||||
| --------- `foo` from trait
|
| --------- `foo` from trait
|
||||||
|
|
||||||
error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions
|
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")]
|
LL | #[target_feature(enable = "sse2")]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -205,7 +205,21 @@ LL | fn foo() {}
|
||||||
= help: add `#![feature(target_feature_11)]` to the crate attributes to enable
|
= 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
|
= 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`.
|
For more information about an error, try `rustc --explain E0046`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue