Rollup merge of #138399 - Bryanskiy:delegation-extern-fn, r=petrochenkov
Delegation: allow foreign fns `reuse` In example: ```rust unsafe extern "C" { fn foo(); } reuse foo as bar; ``` Desugaring before: ```rust fn bar() { foo() //~^ ERROR call to unsafe function `foo` is unsafe and requires unsafe function or block } ``` after: ```rust unsafe extern "C" fn bar() { foo() } ``` Fixes https://github.com/rust-lang/rust/issues/127412 r? `@petrochenkov`
This commit is contained in:
commit
41d6e6e8da
5 changed files with 87 additions and 13 deletions
|
@ -190,14 +190,19 @@ 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,
|
||||
Some(sig) => {
|
||||
let parent = self.tcx.parent(sig_id);
|
||||
// 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 },
|
||||
&[],
|
||||
),
|
||||
let default_safety =
|
||||
if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
|
||||
hir::Safety::Unsafe
|
||||
} else {
|
||||
hir::Safety::Safe
|
||||
};
|
||||
self.lower_fn_header(sig.header, default_safety, &[])
|
||||
}
|
||||
None => self.generate_header_error(),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -753,6 +753,11 @@ impl UnsafeOpKind {
|
|||
span: Span,
|
||||
suggest_unsafe_block: bool,
|
||||
) {
|
||||
if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
|
||||
// The body of the delegation item is synthesized, so it makes no sense
|
||||
// to emit this lint.
|
||||
return;
|
||||
}
|
||||
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| {
|
||||
|
|
|
@ -5117,12 +5117,18 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
|
|||
}
|
||||
|
||||
impl ItemInfoCollector<'_, '_, '_> {
|
||||
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) {
|
||||
fn collect_fn_info(
|
||||
&mut self,
|
||||
header: FnHeader,
|
||||
decl: &FnDecl,
|
||||
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(),
|
||||
header,
|
||||
param_count: decl.inputs.len(),
|
||||
has_self: decl.has_self(),
|
||||
c_variadic: 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);
|
||||
|
@ -5142,7 +5148,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
|
|||
| ItemKind::Trait(box Trait { generics, .. })
|
||||
| ItemKind::TraitAlias(generics, _) => {
|
||||
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.collect_fn_info(sig, item.id, &item.attrs);
|
||||
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
|
||||
}
|
||||
|
||||
let def_id = self.r.local_def_id(item.id);
|
||||
|
@ -5154,8 +5160,17 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
|
|||
self.r.item_generics_num_lifetimes.insert(def_id, count);
|
||||
}
|
||||
|
||||
ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
|
||||
for foreign_item in items {
|
||||
if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
|
||||
let new_header =
|
||||
FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header };
|
||||
self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::ExternCrate(..)
|
||||
|
@ -5175,7 +5190,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
|
|||
|
||||
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.collect_fn_info(sig, item.id, &item.attrs);
|
||||
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
|
||||
}
|
||||
visit::walk_assoc_item(self, item, ctxt);
|
||||
}
|
||||
|
|
22
tests/ui/delegation/foreign-fn.rs
Normal file
22
tests/ui/delegation/foreign-fn.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
#![feature(fn_delegation)]
|
||||
#![allow(incomplete_features)]
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![deny(unused_unsafe)]
|
||||
|
||||
mod to_reuse {
|
||||
unsafe extern "C" {
|
||||
pub fn default_unsafe_foo();
|
||||
pub unsafe fn unsafe_foo();
|
||||
pub safe fn safe_foo();
|
||||
}
|
||||
}
|
||||
|
||||
reuse to_reuse::{default_unsafe_foo, unsafe_foo, safe_foo};
|
||||
|
||||
fn main() {
|
||||
let _: extern "C" fn() = default_unsafe_foo;
|
||||
//~^ ERROR mismatched types
|
||||
let _: extern "C" fn() = unsafe_foo;
|
||||
//~^ ERROR mismatched types
|
||||
let _: extern "C" fn() = safe_foo;
|
||||
}
|
27
tests/ui/delegation/foreign-fn.stderr
Normal file
27
tests/ui/delegation/foreign-fn.stderr
Normal file
|
@ -0,0 +1,27 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/foreign-fn.rs:17:30
|
||||
|
|
||||
LL | let _: extern "C" fn() = default_unsafe_foo;
|
||||
| --------------- ^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected fn pointer `extern "C" fn()`
|
||||
found fn item `unsafe extern "C" fn() {default_unsafe_foo}`
|
||||
= note: unsafe functions cannot be coerced into safe function pointers
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/foreign-fn.rs:19:30
|
||||
|
|
||||
LL | let _: extern "C" fn() = unsafe_foo;
|
||||
| --------------- ^^^^^^^^^^ expected safe fn, found unsafe fn
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected fn pointer `extern "C" fn()`
|
||||
found fn item `unsafe extern "C" fn() {unsafe_foo}`
|
||||
= note: unsafe functions cannot be coerced into safe function pointers
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
Loading…
Add table
Add a link
Reference in a new issue