From bf66723c0ecbadc3b4b24da44fa02b7ea3cd73bb Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 28 Aug 2023 02:37:38 +0000
Subject: [PATCH] Test and note unsafe ctor to fn ptr coercion

Also remove a note that I don't consider to be very useful in context.
---
 .../src/infer/error_reporting/note_and_explain.rs | 10 ++++------
 .../two-mismatch-notes.stderr                     |  1 -
 tests/ui/c-variadic/variadic-ffi-1.stderr         |  2 --
 tests/ui/fn/fn-pointer-mismatch.stderr            |  1 -
 .../fn/signature-error-reporting-under-verbose.rs |  1 -
 ...signature-error-reporting-under-verbose.stderr |  1 -
 tests/ui/issues/issue-10764.stderr                |  1 -
 tests/ui/mismatched_types/normalize-fn-sig.stderr |  1 -
 ...ion-lifetime-bounds-on-fns-where-clause.stderr |  1 -
 ...ple-lifetime-bounds-on-fns-where-clause.stderr |  1 -
 ...regions-fn-subtyping-return-static-fail.stderr |  1 -
 .../regions/regions-lifetime-bounds-on-fns.stderr |  1 -
 tests/ui/reify-intrinsic.stderr                   |  1 -
 .../rfc-2396-target_feature-11/fn-ptr.mir.stderr  |  1 -
 .../rfc-2396-target_feature-11/fn-ptr.thir.stderr |  1 -
 tests/ui/static/static-reference-to-fn-1.stderr   |  1 -
 tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs          | 10 ++++++++++
 tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr      | 15 +++++++++++++++
 18 files changed, 29 insertions(+), 22 deletions(-)
 create mode 100644 tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs
 create mode 100644 tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr

diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 372539d73b1..445f68160d2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -266,12 +266,10 @@ impl<T> Trait<T> for X {
                             }
                         }
                     }
-                    (ty::FnPtr(_), ty::FnDef(def, _))
-                    if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
-                        diag.note(
-                            "when the arguments and return types match, functions can be coerced \
-                             to function pointers",
-                        );
+                    (ty::FnPtr(sig), ty::FnDef(def_id, _)) | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
+                        if tcx.fn_sig(*def_id).skip_binder().unsafety() < sig.unsafety() {
+                            diag.note("unsafe functions cannot be coerced into safe function pointers");
+                        }
                     }
                     _ => {}
                 }
diff --git a/tests/ui/argument-suggestions/two-mismatch-notes.stderr b/tests/ui/argument-suggestions/two-mismatch-notes.stderr
index 38cf23ddc38..70cc60255c7 100644
--- a/tests/ui/argument-suggestions/two-mismatch-notes.stderr
+++ b/tests/ui/argument-suggestions/two-mismatch-notes.stderr
@@ -11,7 +11,6 @@ LL |     foo(f, w);
    |         ^
    = note: expected fn pointer `fn(i32)`
                  found fn item `fn(u32) {f}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 note: expected `Wrapper<i32>`, found `Wrapper<isize>`
   --> $DIR/two-mismatch-notes.rs:10:12
    |
diff --git a/tests/ui/c-variadic/variadic-ffi-1.stderr b/tests/ui/c-variadic/variadic-ffi-1.stderr
index c7899338197..4beea83d8a5 100644
--- a/tests/ui/c-variadic/variadic-ffi-1.stderr
+++ b/tests/ui/c-variadic/variadic-ffi-1.stderr
@@ -46,7 +46,6 @@ LL |         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
    |
    = note: expected fn pointer `unsafe extern "C" fn(_, _)`
                  found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error[E0308]: mismatched types
   --> $DIR/variadic-ffi-1.rs:26:54
@@ -58,7 +57,6 @@ LL |         let y: extern "C" fn(f: isize, x: u8, ...) = bar;
    |
    = note: expected fn pointer `extern "C" fn(_, _, ...)`
                  found fn item `extern "C" fn(_, _) {bar}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error[E0617]: can't pass `f32` to variadic function
   --> $DIR/variadic-ffi-1.rs:28:19
diff --git a/tests/ui/fn/fn-pointer-mismatch.stderr b/tests/ui/fn/fn-pointer-mismatch.stderr
index a674babcb32..87ece845b83 100644
--- a/tests/ui/fn/fn-pointer-mismatch.stderr
+++ b/tests/ui/fn/fn-pointer-mismatch.stderr
@@ -80,7 +80,6 @@ LL |     let e: &fn(u32) -> u32 = &foo;
    = note: expected reference `&fn(u32) -> u32`
               found reference `&fn(u32) -> u32 {foo}`
    = note: fn items are distinct from fn pointers
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 help: consider casting to a fn pointer
    |
 LL |     let e: &fn(u32) -> u32 = &(foo as fn(u32) -> u32);
diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.rs b/tests/ui/fn/signature-error-reporting-under-verbose.rs
index 12ff113c913..d00cbd8a0f2 100644
--- a/tests/ui/fn/signature-error-reporting-under-verbose.rs
+++ b/tests/ui/fn/signature-error-reporting-under-verbose.rs
@@ -12,5 +12,4 @@ fn main() {
     //~| NOTE expected fn pointer, found fn item
     //~| NOTE expected fn pointer `fn(i32, u32)`
     //~| NOTE arguments to this function are incorrect
-    //~| NOTE when the arguments and return types match, functions can be coerced to function pointers
 }
diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.stderr b/tests/ui/fn/signature-error-reporting-under-verbose.stderr
index f4498db7259..067ee824d5d 100644
--- a/tests/ui/fn/signature-error-reporting-under-verbose.stderr
+++ b/tests/ui/fn/signature-error-reporting-under-verbose.stderr
@@ -8,7 +8,6 @@ LL |     needs_ptr(foo);
    |
    = note: expected fn pointer `fn(i32, u32)`
                  found fn item `fn(i32, i32) {foo}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 note: function defined here
   --> $DIR/signature-error-reporting-under-verbose.rs:5:4
    |
diff --git a/tests/ui/issues/issue-10764.stderr b/tests/ui/issues/issue-10764.stderr
index fcb45affe2c..4d8a85a1397 100644
--- a/tests/ui/issues/issue-10764.stderr
+++ b/tests/ui/issues/issue-10764.stderr
@@ -8,7 +8,6 @@ LL | fn main() { f(bar) }
    |
    = note: expected fn pointer `fn()`
                  found fn item `extern "C" fn() {bar}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 note: function defined here
   --> $DIR/issue-10764.rs:1:4
    |
diff --git a/tests/ui/mismatched_types/normalize-fn-sig.stderr b/tests/ui/mismatched_types/normalize-fn-sig.stderr
index e3a0646550c..252e56387ba 100644
--- a/tests/ui/mismatched_types/normalize-fn-sig.stderr
+++ b/tests/ui/mismatched_types/normalize-fn-sig.stderr
@@ -8,7 +8,6 @@ LL |     needs_i32_ref_fn(foo::<()>);
    |
    = note: expected fn pointer `fn(&'static i32, i32)`
                  found fn item `fn(i32, &'static i32) {foo::<()>}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 note: function defined here
   --> $DIR/normalize-fn-sig.rs:11:4
    |
diff --git a/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr b/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
index f2328cf3b24..a9a92b7a695 100644
--- a/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
+++ b/tests/ui/regions/region-lifetime-bounds-on-fns-where-clause.stderr
@@ -8,7 +8,6 @@ LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |
    = note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
                  found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error: aborting due to previous error
 
diff --git a/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr b/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
index 9c5004981d5..e96559937d4 100644
--- a/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
+++ b/tests/ui/regions/region-multiple-lifetime-bounds-on-fns-where-clause.stderr
@@ -8,7 +8,6 @@ LL |     let _: fn(&mut &isize, &mut &isize, &mut &isize) = a;
    |
    = note: expected fn pointer `for<'a, 'b, 'c, 'd, 'e, 'f> fn(&'a mut &'b isize, &'c mut &'d isize, &'e mut &'f isize)`
                  found fn item `for<'a, 'b, 'c> fn(&'a mut &isize, &'b mut &isize, &'c mut &isize) {a::<'_, '_, '_>}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error: aborting due to previous error
 
diff --git a/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr b/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr
index 766a3d0337c..8d82ff958ff 100644
--- a/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr
+++ b/tests/ui/regions/regions-fn-subtyping-return-static-fail.stderr
@@ -8,7 +8,6 @@ LL |     want_G(baz);
    |
    = note: expected fn pointer `for<'cx> fn(&'cx S) -> &'static S`
                  found fn item `for<'a> fn(&'a S) -> &'a S {baz}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 note: function defined here
   --> $DIR/regions-fn-subtyping-return-static-fail.rs:20:4
    |
diff --git a/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr b/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr
index 2fab2986567..53a5612d24f 100644
--- a/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr
+++ b/tests/ui/regions/regions-lifetime-bounds-on-fns.stderr
@@ -8,7 +8,6 @@ LL |     let _: fn(&mut &isize, &mut &isize) = a;
    |
    = note: expected fn pointer `for<'a, 'b, 'c, 'd> fn(&'a mut &'b isize, &'c mut &'d isize)`
                  found fn item `for<'a, 'b> fn(&'a mut &isize, &'b mut &isize) {a::<'_, '_>}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error: aborting due to previous error
 
diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/reify-intrinsic.stderr
index 9f9034a30c7..310b6c224e0 100644
--- a/tests/ui/reify-intrinsic.stderr
+++ b/tests/ui/reify-intrinsic.stderr
@@ -8,7 +8,6 @@ LL |     let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr
    |
    = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize`
                  found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}`
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 
 error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid
   --> $DIR/reify-intrinsic.rs:11:13
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
index b0ac5dc44ad..e08ffe42d6a 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr
@@ -13,7 +13,6 @@ LL |     let foo: fn() = foo;
                  found fn item `fn() {foo}`
    = note: fn items are distinct from fn pointers
    = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 help: consider casting to a fn pointer
    |
 LL |     let foo: fn() = foo as fn();
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
index b0ac5dc44ad..e08ffe42d6a 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
@@ -13,7 +13,6 @@ LL |     let foo: fn() = foo;
                  found fn item `fn() {foo}`
    = note: fn items are distinct from fn pointers
    = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 help: consider casting to a fn pointer
    |
 LL |     let foo: fn() = foo as fn();
diff --git a/tests/ui/static/static-reference-to-fn-1.stderr b/tests/ui/static/static-reference-to-fn-1.stderr
index b68352b5183..86c4eaa7eb4 100644
--- a/tests/ui/static/static-reference-to-fn-1.stderr
+++ b/tests/ui/static/static-reference-to-fn-1.stderr
@@ -7,7 +7,6 @@ LL |         func: &foo,
    = note: expected reference `&fn() -> Option<isize>`
               found reference `&fn() -> Option<isize> {foo}`
    = note: fn items are distinct from fn pointers
-   = note: when the arguments and return types match, functions can be coerced to function pointers
 help: consider casting to a fn pointer
    |
 LL |         func: &(foo as fn() -> Option<isize>),
diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs
new file mode 100644
index 00000000000..a91e579510d
--- /dev/null
+++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.rs
@@ -0,0 +1,10 @@
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+#[rustc_layout_scalar_valid_range_start(2)]
+struct NonZeroAndOneU8(u8);
+
+fn main() {
+    let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
new file mode 100644
index 00000000000..660c4070451
--- /dev/null
+++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
@@ -0,0 +1,15 @@
+error[E0308]: mismatched types
+  --> $DIR/ranged-ctor-as-fn-ptr.rs:8:40
+   |
+LL |     let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
+   |            -------------------------   ^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   |            |
+   |            expected due to this
+   |
+   = note:      expected fn pointer `fn(_) -> NonZeroAndOneU8`
+           found struct constructor `unsafe fn(_) -> NonZeroAndOneU8 {NonZeroAndOneU8}`
+   = note: unsafe functions cannot be coerced into safe function pointers
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.