Skip to content

Commit fb9e171

Browse files
committed
Only implement Fn* traits for extern "Rust" safe function pointers.
1 parent 84c47b8 commit fb9e171

File tree

4 files changed

+98
-2
lines changed

4 files changed

+98
-2
lines changed

compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashMap;
22
use rustc_hir::{def_id::DefId, Movability, Mutability};
33
use rustc_infer::traits::query::NoSolution;
44
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
5+
use rustc_target::spec::abi::Abi;
56

67
use crate::solve::EvalCtxt;
78

@@ -194,7 +195,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
194195
.subst(tcx, substs)
195196
.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
196197
)),
197-
ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
198+
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
199+
ty::FnPtr(sig) => {
200+
if let ty::FnSig {
201+
unsafety: rustc_hir::Unsafety::Normal,
202+
abi: Abi::Rust,
203+
c_variadic: false,
204+
..
205+
} = sig.skip_binder()
206+
{
207+
Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
208+
} else {
209+
Err(NoSolution)
210+
}
211+
}
198212
ty::Closure(_, substs) => {
199213
let closure_substs = substs.as_closure();
200214
match closure_substs.kind_ty().to_opt_closure_kind() {

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
291291
return;
292292
}
293293

294+
// Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable
295+
// until the old solver (and thus this function) is removed.
296+
294297
// Okay to skip binder because what we are inspecting doesn't involve bound regions.
295298
let self_ty = obligation.self_ty().skip_binder();
296299
match *self_ty.kind() {
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,28 @@
11
// compile-flags: -Ztrait-solver=next
2-
// check-pass
32

43
fn require_fn(_: impl Fn() -> i32) {}
54

65
fn f() -> i32 {
76
1i32
87
}
98

9+
extern "C" fn g() -> i32 {
10+
2i32
11+
}
12+
13+
unsafe fn h() -> i32 {
14+
2i32
15+
}
16+
1017
fn main() {
1118
require_fn(f);
1219
require_fn(f as fn() -> i32);
20+
require_fn(f as unsafe fn() -> i32);
21+
//~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
22+
//~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
23+
require_fn(g);
24+
require_fn(g as extern "C" fn() -> i32);
25+
//~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
26+
//~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
27+
require_fn(h);
1328
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
2+
--> $DIR/fn-trait.rs:20:16
3+
|
4+
LL | require_fn(f as unsafe fn() -> i32);
5+
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
6+
| |
7+
| required by a bound introduced by this call
8+
|
9+
= help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
10+
= note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
11+
note: required by a bound in `require_fn`
12+
--> $DIR/fn-trait.rs:3:23
13+
|
14+
LL | fn require_fn(_: impl Fn() -> i32) {}
15+
| ^^^^^^^^^^^ required by this bound in `require_fn`
16+
17+
error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
18+
--> $DIR/fn-trait.rs:20:16
19+
|
20+
LL | require_fn(f as unsafe fn() -> i32);
21+
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ
22+
| |
23+
| required by a bound introduced by this call
24+
|
25+
note: required by a bound in `require_fn`
26+
--> $DIR/fn-trait.rs:3:31
27+
|
28+
LL | fn require_fn(_: impl Fn() -> i32) {}
29+
| ^^^ required by this bound in `require_fn`
30+
31+
error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
32+
--> $DIR/fn-trait.rs:24:16
33+
|
34+
LL | require_fn(g as extern "C" fn() -> i32);
35+
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
36+
| |
37+
| required by a bound introduced by this call
38+
|
39+
= help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32`
40+
= note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
41+
note: required by a bound in `require_fn`
42+
--> $DIR/fn-trait.rs:3:23
43+
|
44+
LL | fn require_fn(_: impl Fn() -> i32) {}
45+
| ^^^^^^^^^^^ required by this bound in `require_fn`
46+
47+
error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
48+
--> $DIR/fn-trait.rs:24:16
49+
|
50+
LL | require_fn(g as extern "C" fn() -> i32);
51+
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
52+
| |
53+
| required by a bound introduced by this call
54+
|
55+
note: required by a bound in `require_fn`
56+
--> $DIR/fn-trait.rs:3:31
57+
|
58+
LL | fn require_fn(_: impl Fn() -> i32) {}
59+
| ^^^ required by this bound in `require_fn`
60+
61+
error: aborting due to 4 previous errors
62+
63+
Some errors have detailed explanations: E0271, E0277.
64+
For more information about an error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)