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

Commit f99d3b9

Browse files
committedMar 12, 2025
Delegation: allow foreign fns reuse
1 parent 57a4736 commit f99d3b9

File tree

5 files changed

+87
-13
lines changed

5 files changed

+87
-13
lines changed
 

‎compiler/rustc_ast_lowering/src/delegation.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -190,14 +190,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
190190
) -> hir::FnSig<'hir> {
191191
let header = if let Some(local_sig_id) = sig_id.as_local() {
192192
match self.resolver.delegation_fn_sigs.get(&local_sig_id) {
193-
Some(sig) => self.lower_fn_header(
194-
sig.header,
193+
Some(sig) => {
194+
let parent = self.tcx.parent(sig_id);
195195
// HACK: we override the default safety instead of generating attributes from the ether.
196196
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
197197
// and here we need the hir attributes.
198-
if sig.target_feature { hir::Safety::Unsafe } else { hir::Safety::Safe },
199-
&[],
200-
),
198+
let default_safety =
199+
if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod {
200+
hir::Safety::Unsafe
201+
} else {
202+
hir::Safety::Safe
203+
};
204+
self.lower_fn_header(sig.header, default_safety, &[])
205+
}
201206
None => self.generate_header_error(),
202207
}
203208
} else {

‎compiler/rustc_mir_build/src/check_unsafety.rs

+5
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,11 @@ impl UnsafeOpKind {
753753
span: Span,
754754
suggest_unsafe_block: bool,
755755
) {
756+
if tcx.hir().opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
757+
// The body of the delegation item is synthesized, so it makes no sense
758+
// to emit this lint.
759+
return;
760+
}
756761
let parent_id = tcx.hir_get_parent_item(hir_id);
757762
let parent_owner = tcx.hir_owner_node(parent_id);
758763
let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {

‎compiler/rustc_resolve/src/late.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -5101,12 +5101,18 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
51015101
}
51025102

51035103
impl ItemInfoCollector<'_, '_, '_> {
5104-
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) {
5104+
fn collect_fn_info(
5105+
&mut self,
5106+
header: FnHeader,
5107+
decl: &FnDecl,
5108+
id: NodeId,
5109+
attrs: &[Attribute],
5110+
) {
51055111
let sig = DelegationFnSig {
5106-
header: sig.header,
5107-
param_count: sig.decl.inputs.len(),
5108-
has_self: sig.decl.has_self(),
5109-
c_variadic: sig.decl.c_variadic(),
5112+
header,
5113+
param_count: decl.inputs.len(),
5114+
has_self: decl.has_self(),
5115+
c_variadic: decl.c_variadic(),
51105116
target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)),
51115117
};
51125118
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
@@ -5126,7 +5132,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51265132
| ItemKind::Trait(box Trait { generics, .. })
51275133
| ItemKind::TraitAlias(generics, _) => {
51285134
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5129-
self.collect_fn_info(sig, item.id, &item.attrs);
5135+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
51305136
}
51315137

51325138
let def_id = self.r.local_def_id(item.id);
@@ -5138,8 +5144,17 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51385144
self.r.item_generics_num_lifetimes.insert(def_id, count);
51395145
}
51405146

5147+
ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
5148+
for foreign_item in items {
5149+
if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
5150+
let new_header =
5151+
FnHeader { ext: Extern::from_abi(abi, *extern_span), ..sig.header };
5152+
self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
5153+
}
5154+
}
5155+
}
5156+
51415157
ItemKind::Mod(..)
5142-
| ItemKind::ForeignMod(..)
51435158
| ItemKind::Static(..)
51445159
| ItemKind::Use(..)
51455160
| ItemKind::ExternCrate(..)
@@ -5159,7 +5174,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51595174

51605175
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
51615176
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5162-
self.collect_fn_info(sig, item.id, &item.attrs);
5177+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
51635178
}
51645179
visit::walk_assoc_item(self, item, ctxt);
51655180
}

‎tests/ui/delegation/foreign-fn.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![feature(fn_delegation)]
2+
#![allow(incomplete_features)]
3+
#![deny(unsafe_op_in_unsafe_fn)]
4+
#![deny(unused_unsafe)]
5+
6+
mod to_reuse {
7+
unsafe extern "C" {
8+
pub fn default_unsafe_foo();
9+
pub unsafe fn unsafe_foo();
10+
pub safe fn safe_foo();
11+
}
12+
}
13+
14+
reuse to_reuse::{default_unsafe_foo, unsafe_foo, safe_foo};
15+
16+
fn main() {
17+
let _: extern "C" fn() = default_unsafe_foo;
18+
//~^ ERROR mismatched types
19+
let _: extern "C" fn() = unsafe_foo;
20+
//~^ ERROR mismatched types
21+
let _: extern "C" fn() = safe_foo;
22+
}

‎tests/ui/delegation/foreign-fn.stderr

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/foreign-fn.rs:17:30
3+
|
4+
LL | let _: extern "C" fn() = default_unsafe_foo;
5+
| --------------- ^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
6+
| |
7+
| expected due to this
8+
|
9+
= note: expected fn pointer `extern "C" fn()`
10+
found fn item `unsafe extern "C" fn() {default_unsafe_foo}`
11+
= note: unsafe functions cannot be coerced into safe function pointers
12+
13+
error[E0308]: mismatched types
14+
--> $DIR/foreign-fn.rs:19:30
15+
|
16+
LL | let _: extern "C" fn() = unsafe_foo;
17+
| --------------- ^^^^^^^^^^ expected safe fn, found unsafe fn
18+
| |
19+
| expected due to this
20+
|
21+
= note: expected fn pointer `extern "C" fn()`
22+
found fn item `unsafe extern "C" fn() {unsafe_foo}`
23+
= note: unsafe functions cannot be coerced into safe function pointers
24+
25+
error: aborting due to 2 previous errors
26+
27+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)
Failed to load comments.