Skip to content

Commit a00413f

Browse files
committed
Also check function items' signatures for Fn* trait compatibility
1 parent 91d9131 commit a00413f

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed

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

+14-5
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
189189
goal_kind: ty::ClosureKind,
190190
) -> Result<Option<ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>)>>, NoSolution> {
191191
match *self_ty.kind() {
192-
ty::FnDef(def_id, substs) => Ok(Some(
193-
tcx.fn_sig(def_id)
194-
.subst(tcx, substs)
195-
.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
196-
)),
192+
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
193+
ty::FnDef(def_id, substs) => {
194+
let sig = tcx.fn_sig(def_id);
195+
if sig.skip_binder().is_fn_trait_compatible()
196+
&& tcx.codegen_fn_attrs(def_id).target_features.is_empty()
197+
{
198+
Ok(Some(
199+
sig.subst(tcx, substs)
200+
.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
201+
))
202+
} else {
203+
Err(NoSolution)
204+
}
205+
}
197206
// keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
198207
ty::FnPtr(sig) => {
199208
if sig.is_fn_trait_compatible() {

tests/ui/traits/new-solver/fn-trait.rs

+4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ fn main() {
2121
//~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
2222
//~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
2323
require_fn(g);
24+
//~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
25+
//~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 {g} as FnOnce<()>>::Output == i32`
2426
require_fn(g as extern "C" fn() -> i32);
2527
//~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
2628
//~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
2729
require_fn(h);
30+
//~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
31+
//~| ERROR: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
2832
}

tests/ui/traits/new-solver/fn-trait.stderr

+63-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,38 @@ note: required by a bound in `require_fn`
2828
LL | fn require_fn(_: impl Fn() -> i32) {}
2929
| ^^^ required by this bound in `require_fn`
3030

31+
error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
32+
--> $DIR/fn-trait.rs:23:16
33+
|
34+
LL | require_fn(g);
35+
| ---------- ^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32 {g}`
36+
| |
37+
| required by a bound introduced by this call
38+
|
39+
= help: the trait `Fn<()>` is not implemented for fn item `extern "C" fn() -> i32 {g}`
40+
= note: wrap the `extern "C" fn() -> i32 {g}` 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 {g} as FnOnce<()>>::Output == i32`
48+
--> $DIR/fn-trait.rs:23:16
49+
|
50+
LL | require_fn(g);
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+
3161
error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
32-
--> $DIR/fn-trait.rs:24:16
62+
--> $DIR/fn-trait.rs:26:16
3363
|
3464
LL | require_fn(g as extern "C" fn() -> i32);
3565
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
@@ -45,7 +75,7 @@ LL | fn require_fn(_: impl Fn() -> i32) {}
4575
| ^^^^^^^^^^^ required by this bound in `require_fn`
4676

4777
error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
48-
--> $DIR/fn-trait.rs:24:16
78+
--> $DIR/fn-trait.rs:26:16
4979
|
5080
LL | require_fn(g as extern "C" fn() -> i32);
5181
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
@@ -58,7 +88,37 @@ note: required by a bound in `require_fn`
5888
LL | fn require_fn(_: impl Fn() -> i32) {}
5989
| ^^^ required by this bound in `require_fn`
6090

61-
error: aborting due to 4 previous errors
91+
error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32 {h}`
92+
--> $DIR/fn-trait.rs:29:16
93+
|
94+
LL | require_fn(h);
95+
| ---------- ^ call the function in a closure: `|| unsafe { /* code */ }`
96+
| |
97+
| required by a bound introduced by this call
98+
|
99+
= help: the trait `Fn<()>` is not implemented for fn item `unsafe fn() -> i32 {h}`
100+
= note: wrap the `unsafe fn() -> i32 {h}` in a closure with no arguments: `|| { /* code */ }`
101+
note: required by a bound in `require_fn`
102+
--> $DIR/fn-trait.rs:3:23
103+
|
104+
LL | fn require_fn(_: impl Fn() -> i32) {}
105+
| ^^^^^^^^^^^ required by this bound in `require_fn`
106+
107+
error[E0271]: type mismatch resolving `<unsafe fn() -> i32 {h} as FnOnce<()>>::Output == i32`
108+
--> $DIR/fn-trait.rs:29:16
109+
|
110+
LL | require_fn(h);
111+
| ---------- ^ types differ
112+
| |
113+
| required by a bound introduced by this call
114+
|
115+
note: required by a bound in `require_fn`
116+
--> $DIR/fn-trait.rs:3:31
117+
|
118+
LL | fn require_fn(_: impl Fn() -> i32) {}
119+
| ^^^ required by this bound in `require_fn`
120+
121+
error: aborting due to 8 previous errors
62122

63123
Some errors have detailed explanations: E0271, E0277.
64124
For more information about an error, try `rustc --explain E0271`.

0 commit comments

Comments
 (0)