about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2020-06-13 11:03:31 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2020-06-13 11:03:31 -0400
commitc98b4c8fdde7812d7af5a060a1e22fd7e3775d3f (patch)
tree0a6ea958d39081dcfb46dc2982cb51ca484c07ca
parent144206e6d8c1ab4ffdbaf6d7b0f5a4201c0f2da4 (diff)
downloadrust-c98b4c8fdde7812d7af5a060a1e22fd7e3775d3f.tar.gz
rust-c98b4c8fdde7812d7af5a060a1e22fd7e3775d3f.zip
Add error note when trying fn as Fn trait
-rw-r--r--src/librustc_trait_selection/traits/error_reporting/mod.rs21
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs10
-rw-r--r--src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr47
3 files changed, 74 insertions, 4 deletions
diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs
index 1b72a4bf84f..39530853318 100644
--- a/src/librustc_trait_selection/traits/error_reporting/mod.rs
+++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs
@@ -286,6 +286,20 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             .starts_with("std::convert::From<");
                         let is_unsize =
                             { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
+                        let is_fn_trait = [
+                            self.tcx.lang_items().fn_trait(),
+                            self.tcx.lang_items().fn_mut_trait(),
+                            self.tcx.lang_items().fn_once_trait(),
+                        ]
+                        .contains(&Some(trait_ref.def_id()));
+                        let is_safe_target_feature_fn =
+                            if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind {
+                                trait_ref.skip_binder().self_ty().fn_sig(self.tcx).unsafety()
+                                    == hir::Unsafety::Normal
+                                    && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
+                            } else {
+                                false
+                            };
                         let (message, note) = if is_try && is_from {
                             (
                                 Some(format!(
@@ -427,6 +441,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             );
                         }
 
+                        if is_fn_trait && is_safe_target_feature_fn {
+                            err.note(&format!(
+                                "`{}` has `#[target_feature]` and is unsafe to call",
+                                trait_ref.skip_binder().self_ty(),
+                            ));
+                        }
+
                         // Try to report a help message
                         if !trait_ref.has_infer_types_or_consts()
                             && self.predicate_can_apply(obligation.param_env, trait_ref)
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
index 58070b69bc1..5c838fd719c 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs
@@ -5,6 +5,9 @@
 #[target_feature(enable = "avx")]
 fn foo() {}
 
+#[target_feature(enable = "avx")]
+unsafe fn foo_unsafe() {}
+
 fn call(f: impl Fn()) {
     f()
 }
@@ -21,4 +24,11 @@ fn main() {
     call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
     call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
     call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
+
+    call(foo_unsafe);
+    //~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
+    call_mut(foo_unsafe);
+    //~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
+    call_once(foo_unsafe);
+    //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
 }
diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
index 6dcf31b4c74..3ae85af76d3 100644
--- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
+++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr
@@ -1,5 +1,5 @@
 error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:21:10
+  --> $DIR/fn-traits.rs:24:10
    |
 LL | fn call(f: impl Fn()) {
    |                 ---- required by this bound in `call`
@@ -9,9 +9,10 @@ LL |     call(foo);
    |
    = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}`
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+   = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
 
 error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:22:14
+  --> $DIR/fn-traits.rs:25:14
    |
 LL | fn call_mut(f: impl FnMut()) {
    |                     ------- required by this bound in `call_mut`
@@ -21,9 +22,10 @@ LL |     call_mut(foo);
    |
    = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}`
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+   = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
 
 error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}`
-  --> $DIR/fn-traits.rs:23:15
+  --> $DIR/fn-traits.rs:26:15
    |
 LL | fn call_once(f: impl FnOnce()) {
    |                      -------- required by this bound in `call_once`
@@ -33,7 +35,44 @@ LL |     call_once(foo);
    |
    = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}`
    = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }
+   = note: `fn() {foo}` has `#[target_feature]` and is unsafe to call
 
-error: aborting due to 3 previous errors
+error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
+  --> $DIR/fn-traits.rs:28:10
+   |
+LL | fn call(f: impl Fn()) {
+   |                 ---- required by this bound in `call`
+...
+LL |     call(foo_unsafe);
+   |          ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}`
+   |
+   = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+   = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+
+error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
+  --> $DIR/fn-traits.rs:30:14
+   |
+LL | fn call_mut(f: impl FnMut()) {
+   |                     ------- required by this bound in `call_mut`
+...
+LL |     call_mut(foo_unsafe);
+   |              ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}`
+   |
+   = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+   = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+
+error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
+  --> $DIR/fn-traits.rs:32:15
+   |
+LL | fn call_once(f: impl FnOnce()) {
+   |                      -------- required by this bound in `call_once`
+...
+LL |     call_once(foo_unsafe);
+   |               ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}`
+   |
+   = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}`
+   = note: wrap the `unsafe fn() {foo_unsafe}` in a closure with no arguments: `|| { /* code */ }
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.