Skip to content

Commit ba6ccfc

Browse files
authored
Unrolled build for rust-lang#138399
Rollup merge of rust-lang#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 rust-lang#127412 r? `@petrochenkov`
2 parents 52daa7d + 63447f2 commit ba6ccfc

File tree

5 files changed

+87
-13
lines changed

5 files changed

+87
-13
lines changed

Diff for: 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 {

Diff for: 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| {

Diff for: compiler/rustc_resolve/src/late.rs

+23-8
Original file line numberDiff line numberDiff line change
@@ -5117,12 +5117,18 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> {
51175117
}
51185118

51195119
impl ItemInfoCollector<'_, '_, '_> {
5120-
fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) {
5120+
fn collect_fn_info(
5121+
&mut self,
5122+
header: FnHeader,
5123+
decl: &FnDecl,
5124+
id: NodeId,
5125+
attrs: &[Attribute],
5126+
) {
51215127
let sig = DelegationFnSig {
5122-
header: sig.header,
5123-
param_count: sig.decl.inputs.len(),
5124-
has_self: sig.decl.has_self(),
5125-
c_variadic: sig.decl.c_variadic(),
5128+
header,
5129+
param_count: decl.inputs.len(),
5130+
has_self: decl.has_self(),
5131+
c_variadic: decl.c_variadic(),
51265132
target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)),
51275133
};
51285134
self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig);
@@ -5142,7 +5148,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51425148
| ItemKind::Trait(box Trait { generics, .. })
51435149
| ItemKind::TraitAlias(generics, _) => {
51445150
if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5145-
self.collect_fn_info(sig, item.id, &item.attrs);
5151+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
51465152
}
51475153

51485154
let def_id = self.r.local_def_id(item.id);
@@ -5154,8 +5160,17 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51545160
self.r.item_generics_num_lifetimes.insert(def_id, count);
51555161
}
51565162

5163+
ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => {
5164+
for foreign_item in items {
5165+
if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind {
5166+
let new_header =
5167+
FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header };
5168+
self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs);
5169+
}
5170+
}
5171+
}
5172+
51575173
ItemKind::Mod(..)
5158-
| ItemKind::ForeignMod(..)
51595174
| ItemKind::Static(..)
51605175
| ItemKind::Use(..)
51615176
| ItemKind::ExternCrate(..)
@@ -5175,7 +5190,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
51755190

51765191
fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) {
51775192
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
5178-
self.collect_fn_info(sig, item.id, &item.attrs);
5193+
self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs);
51795194
}
51805195
visit::walk_assoc_item(self, item, ctxt);
51815196
}

Diff for: 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+
}

Diff for: 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)