Skip to content

Commit c98b4c8

Browse files
committed
Add error note when trying fn as Fn trait
1 parent 144206e commit c98b4c8

File tree

3 files changed

+74
-4
lines changed

3 files changed

+74
-4
lines changed

src/librustc_trait_selection/traits/error_reporting/mod.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
286286
.starts_with("std::convert::From<");
287287
let is_unsize =
288288
{ Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
289+
let is_fn_trait = [
290+
self.tcx.lang_items().fn_trait(),
291+
self.tcx.lang_items().fn_mut_trait(),
292+
self.tcx.lang_items().fn_once_trait(),
293+
]
294+
.contains(&Some(trait_ref.def_id()));
295+
let is_safe_target_feature_fn =
296+
if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind {
297+
trait_ref.skip_binder().self_ty().fn_sig(self.tcx).unsafety()
298+
== hir::Unsafety::Normal
299+
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
300+
} else {
301+
false
302+
};
289303
let (message, note) = if is_try && is_from {
290304
(
291305
Some(format!(
@@ -427,6 +441,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
427441
);
428442
}
429443

444+
if is_fn_trait && is_safe_target_feature_fn {
445+
err.note(&format!(
446+
"`{}` has `#[target_feature]` and is unsafe to call",
447+
trait_ref.skip_binder().self_ty(),
448+
));
449+
}
450+
430451
// Try to report a help message
431452
if !trait_ref.has_infer_types_or_consts()
432453
&& self.predicate_can_apply(obligation.param_env, trait_ref)

src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#[target_feature(enable = "avx")]
66
fn foo() {}
77

8+
#[target_feature(enable = "avx")]
9+
unsafe fn foo_unsafe() {}
10+
811
fn call(f: impl Fn()) {
912
f()
1013
}
@@ -21,4 +24,11 @@ fn main() {
2124
call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
2225
call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
2326
call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
27+
28+
call(foo_unsafe);
29+
//~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
30+
call_mut(foo_unsafe);
31+
//~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
32+
call_once(foo_unsafe);
33+
//~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
2434
}

src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
2-
--> $DIR/fn-traits.rs:21:10
2+
--> $DIR/fn-traits.rs:24:10
33
|
44
LL | fn call(f: impl Fn()) {
55
| ---- required by this bound in `call`
@@ -9,9 +9,10 @@ LL | call(foo);
99
|
1010
= help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}`
1111
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
12+
= note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
1213

1314
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
14-
--> $DIR/fn-traits.rs:22:14
15+
--> $DIR/fn-traits.rs:25:14
1516
|
1617
LL | fn call_mut(f: impl FnMut()) {
1718
| ------- required by this bound in `call_mut`
@@ -21,9 +22,10 @@ LL | call_mut(foo);
2122
|
2223
= help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}`
2324
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
25+
= note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
2426

2527
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
26-
--> $DIR/fn-traits.rs:23:15
28+
--> $DIR/fn-traits.rs:26:15
2729
|
2830
LL | fn call_once(f: impl FnOnce()) {
2931
| -------- required by this bound in `call_once`
@@ -33,7 +35,44 @@ LL | call_once(foo);
3335
|
3436
= help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}`
3537
= note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
38+
= note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
3639

37-
error: aborting due to 3 previous errors
40+
error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
41+
--> $DIR/fn-traits.rs:28:10
42+
|
43+
LL | fn call(f: impl Fn()) {
44+
| ---- required by this bound in `call`
45+
...
46+
LL | call(foo_unsafe);
47+
| ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
48+
|
49+
= help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
50+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
51+
52+
error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
53+
--> $DIR/fn-traits.rs:30:14
54+
|
55+
LL | fn call_mut(f: impl FnMut()) {
56+
| ------- required by this bound in `call_mut`
57+
...
58+
LL | call_mut(foo_unsafe);
59+
| ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
60+
|
61+
= help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
62+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
63+
64+
error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
65+
--> $DIR/fn-traits.rs:32:15
66+
|
67+
LL | fn call_once(f: impl FnOnce()) {
68+
| -------- required by this bound in `call_once`
69+
...
70+
LL | call_once(foo_unsafe);
71+
| ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
72+
|
73+
= help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
74+
= note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
75+
76+
error: aborting due to 6 previous errors
3877

3978
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)