From bec8dbdb602688d6da4f49b7fdd74226f0f9f04c Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 4 Apr 2022 17:37:59 -0700 Subject: [PATCH 1/3] diagnostics: give a special note for unsafe fn / Fn/FnOnce/FnMut Fixes #90073 --- .../src/traits/error_reporting/on_unimplemented.rs | 9 +++++++++ library/core/src/ops/function.rs | 12 ++++++++++++ src/test/ui/closures/coerce-unsafe-to-closure.stderr | 1 + .../unboxed-closures-unsafe-extern-fn.stderr | 3 +++ .../unboxed-closures-wrong-arg-type-extern-fn.stderr | 3 +++ 5 files changed, 28 insertions(+) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d2b1fe2e0df..31b92d52beb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -208,6 +208,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { flags.push((sym::_Self, Some("&[]".to_owned()))); } + if self_ty.is_fn() { + let fn_sig = self_ty.fn_sig(self.tcx); + let shortname = match fn_sig.unsafety() { + hir::Unsafety::Normal => "fn", + hir::Unsafety::Unsafe => "unsafe fn", + }; + flags.push((sym::_Self, Some(shortname.to_owned()))); + } + if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_owned()))); flags.push((sym::_Self, Some(format!("[{}]", aty)))); diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index e5c4798afcb..a7b28471bfe 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -59,6 +59,10 @@ Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), + on( + _Self = "unsafe fn", + note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + ), message = "expected a `{Fn}<{Args}>` closure, found `{Self}`", label = "expected an `Fn<{Args}>` closure, found `{Self}`" )] @@ -139,6 +143,10 @@ pub trait Fn: FnMut { Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), + on( + _Self = "unsafe fn", + note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + ), message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`", label = "expected an `FnMut<{Args}>` closure, found `{Self}`" )] @@ -211,6 +219,10 @@ pub trait FnMut: FnOnce { Args = "()", note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`" ), + on( + _Self = "unsafe fn", + note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + ), message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`", label = "expected an `FnOnce<{Args}>` closure, found `{Self}`" )] diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr index 883348eb98c..57043c335c0 100644 --- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr +++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr @@ -7,6 +7,7 @@ LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); | required by a bound introduced by this call | = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `Option::::map` --> $SRC_DIR/core/src/option.rs:LL:COL | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index c9a20232f35..fcd668c191f 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -7,6 +7,7 @@ LL | let x = call_it(&square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15 | @@ -22,6 +23,7 @@ LL | let y = call_it_mut(&mut square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19 | @@ -37,6 +39,7 @@ LL | let z = call_it_once(square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20 | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 64d57773d70..576806e3956 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -7,6 +7,7 @@ LL | let x = call_it(&square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15 | @@ -22,6 +23,7 @@ LL | let y = call_it_mut(&mut square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19 | @@ -37,6 +39,7 @@ LL | let z = call_it_once(square, 22); | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20 | From dcf7ce8356ce9182d65b0719216ec08db877d5cc Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Mon, 4 Apr 2022 17:54:20 -0700 Subject: [PATCH 2/3] Fix bogus tidy errors --- library/core/src/ops/function.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index a7b28471bfe..19918e0dcea 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -61,6 +61,7 @@ ), on( _Self = "unsafe fn", + // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{Fn}<{Args}>` closure, found `{Self}`", @@ -145,6 +146,7 @@ pub trait Fn: FnMut { ), on( _Self = "unsafe fn", + // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`", @@ -221,6 +223,7 @@ pub trait FnMut: FnOnce { ), on( _Self = "unsafe fn", + // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`", From 6d18fbbc3f1fee9e717ae5f55bd2970d96e2b5cb Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Tue, 5 Apr 2022 11:13:48 -0700 Subject: [PATCH 3/3] diagnostics: tweak error message to give more rationale to unsafe Fn --- library/core/src/ops/function.rs | 9 ++++++--- src/test/ui/closures/coerce-unsafe-to-closure.stderr | 4 ++-- .../rfcs/rfc-2396-target_feature-11/fn-traits.stderr | 6 +++--- .../unboxed-closures-unsafe-extern-fn.stderr | 12 ++++++------ .../unboxed-closures-wrong-arg-type-extern-fn.stderr | 12 ++++++------ 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index 19918e0dcea..ae879078739 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -61,8 +61,9 @@ ), on( _Self = "unsafe fn", + note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string - note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{Fn}<{Args}>` closure, found `{Self}`", label = "expected an `Fn<{Args}>` closure, found `{Self}`" @@ -146,8 +147,9 @@ pub trait Fn: FnMut { ), on( _Self = "unsafe fn", + note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string - note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`", label = "expected an `FnMut<{Args}>` closure, found `{Self}`" @@ -223,8 +225,9 @@ pub trait FnMut: FnOnce { ), on( _Self = "unsafe fn", + note = "unsafe function cannot be called generically without an unsafe block", // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string - note = "unsafe functions must be wrapped in closures: `|| unsafe {{ /* code */ }}`" + label = "call the function in a closure: `|| unsafe {{ /* code */ }}`" ), message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`", label = "expected an `FnOnce<{Args}>` closure, found `{Self}`" diff --git a/src/test/ui/closures/coerce-unsafe-to-closure.stderr b/src/test/ui/closures/coerce-unsafe-to-closure.stderr index 57043c335c0..bd095c2d83d 100644 --- a/src/test/ui/closures/coerce-unsafe-to-closure.stderr +++ b/src/test/ui/closures/coerce-unsafe-to-closure.stderr @@ -2,12 +2,12 @@ error[E0277]: expected a `FnOnce<(&str,)>` closure, found `unsafe extern "rust-i --> $DIR/coerce-unsafe-to-closure.rs:2:44 | LL | let x: Option<&[u8]> = Some("foo").map(std::mem::transmute); - | --- ^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(&str,)>` closure, found `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` + | --- ^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `FnOnce<(&str,)>` is not implemented for `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `Option::::map` --> $SRC_DIR/core/src/option.rs:LL:COL | 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 ea22d1c89b1..94a90a56854 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 @@ -53,7 +53,7 @@ error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:28:10 | LL | call(foo_unsafe); - | ---- ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + | ---- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | @@ -70,7 +70,7 @@ error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 | LL | call_mut(foo_unsafe); - | -------- ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + | -------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | @@ -87,7 +87,7 @@ error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 | LL | call_once(foo_unsafe); - | --------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + | --------- ^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index fcd668c191f..18e133957ba 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -2,12 +2,12 @@ error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r i --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | LL | let x = call_it(&square, 22); - | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ------- ^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:9:15 | @@ -18,12 +18,12 @@ error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&' --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | LL | let y = call_it_mut(&mut square, 22); - | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:12:19 | @@ -34,12 +34,12 @@ error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(& --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | LL | let z = call_it_once(square, 22); - | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` + | ------------ ^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:15:20 | diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 576806e3956..c826af3c4c3 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -2,12 +2,12 @@ error[E0277]: expected a `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isi --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | LL | let x = call_it(&square, 22); - | ------- ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ------- ^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:10:15 | @@ -18,12 +18,12 @@ error[E0277]: expected a `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | LL | let y = call_it_mut(&mut square, 22); - | ----------- ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ----------- ^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_mut` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:13:19 | @@ -34,12 +34,12 @@ error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | LL | let z = call_it_once(square, 22); - | ------------ ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` + | ------------ ^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` - = note: unsafe functions must be wrapped in closures: `|| unsafe { /* code */ }` + = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `call_it_once` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:16:20 |