Skip to content

Commit f5c21fa

Browse files
committed
Delegation: allow foreign fns reuse
1 parent 30f168e commit f5c21fa

File tree

5 files changed

+91
-13
lines changed

5 files changed

+91
-13
lines changed

compiler/rustc_ast_lowering/src/delegation.rs

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

compiler/rustc_mir_build/src/check_unsafety.rs

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

compiler/rustc_resolve/src/late.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -5056,12 +5056,18 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
50565056
}
50575057

50585058
impl ItemInfoCollector<'_, '_, '_> {
5059-
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) {
5059+
fn collect_fn_info(
5060+
&mut self,
5061+
header: FnHeader,
5062+
decl: &FnDecl,
5063+
id: NodeId,
5064+
attrs: &[Attribute],
5065+
) {
50605066
let sig = DelegationFnSig {
5061-
header: sig.header,
5062-
param_count: sig.decl.inputs.len(),
5063-
has_self: sig.decl.has_self(),
5064-
c_variadic: sig.decl.c_variadic(),
5067+
header,
5068+
param_count: decl.inputs.len(),
5069+
has_self: decl.has_self(),
5070+
c_variadic: decl.c_variadic(),
50655071
target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)),
50665072
};
50675073
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
@@ -5081,7 +5087,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
50815087
| ItemKind::Trait(box Trait { generics, .. })
50825088
| ItemKind::TraitAlias(generics, _) => {
50835089
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5084-
self.collect_fn_info(sig, item.id, &item.attrs);
5090+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
50855091
}
50865092

50875093
let def_id = self.r.local_def_id(item.id);
@@ -5093,8 +5099,21 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
50935099
self.r.item_generics_num_lifetimes.insert(def_id, count);
50945100
}
50955101

5102+
ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
5103+
for foreign_item in items {
5104+
if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
5105+
let new_header = FnHeader {
5106+
ext: abi.map_or(Extern::Implicit(*extern_span), |lit| {
5107+
Extern::Explicit(lit, *extern_span)
5108+
}),
5109+
..sig.header
5110+
};
5111+
self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
5112+
}
5113+
}
5114+
}
5115+
50965116
ItemKind::Mod(..)
5097-
| ItemKind::ForeignMod(..)
50985117
| ItemKind::Static(..)
50995118
| ItemKind::Use(..)
51005119
| ItemKind::ExternCrate(..)
@@ -5114,7 +5133,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51145133

51155134
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
51165135
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5117-
self.collect_fn_info(sig, item.id, &item.attrs);
5136+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
51185137
}
51195138
visit::walk_assoc_item(self, item, ctxt);
51205139
}

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)