about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-03-21 11:11:32 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-03-21 11:11:32 +0000
commitfb9e171ab7b0303fc983b6955e684ebb2a0f5944 (patch)
tree27bb9cf155a9cb76d3b459825c6b212ceb2d3e2b
parent84c47b8279b39e165dfebeb529eb6d92592e4f8d (diff)
downloadrust-fb9e171ab7b0303fc983b6955e684ebb2a0f5944.tar.gz
rust-fb9e171ab7b0303fc983b6955e684ebb2a0f5944.zip
Only implement Fn* traits for extern "Rust" safe function pointers.
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs3
-rw-r--r--tests/ui/traits/new-solver/fn-trait.rs17
-rw-r--r--tests/ui/traits/new-solver/fn-trait.stderr64
4 files changed, 98 insertions, 2 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index d7d93377cf1..51a1a88f8e7 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_target::spec::abi::Abi;
 
 use crate::solve::EvalCtxt;
 
@@ -194,7 +195,20 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
                 .subst(tcx, substs)
                 .map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())),
         )),
-        ty::FnPtr(sig) => Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output())))),
+        // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed.
+        ty::FnPtr(sig) => {
+            if let ty::FnSig {
+                unsafety: rustc_hir::Unsafety::Normal,
+                abi: Abi::Rust,
+                c_variadic: false,
+                ..
+            } = sig.skip_binder()
+            {
+                Ok(Some(sig.map_bound(|sig| (tcx.mk_tup(sig.inputs()), sig.output()))))
+            } else {
+                Err(NoSolution)
+            }
+        }
         ty::Closure(_, substs) => {
             let closure_substs = substs.as_closure();
             match closure_substs.kind_ty().to_opt_closure_kind() {
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 3182af989f0..2b3f003353c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -291,6 +291,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
+        // Keep this funtion in sync with extract_tupled_inputs_and_output_from_callable
+        // until the old solver (and thus this function) is removed.
+
         // Okay to skip binder because what we are inspecting doesn't involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
         match *self_ty.kind() {
diff --git a/tests/ui/traits/new-solver/fn-trait.rs b/tests/ui/traits/new-solver/fn-trait.rs
index d566ead105c..8967858a8ba 100644
--- a/tests/ui/traits/new-solver/fn-trait.rs
+++ b/tests/ui/traits/new-solver/fn-trait.rs
@@ -1,5 +1,4 @@
 // compile-flags: -Ztrait-solver=next
-// check-pass
 
 fn require_fn(_: impl Fn() -> i32) {}
 
@@ -7,7 +6,23 @@ fn f() -> i32 {
     1i32
 }
 
+extern "C" fn g() -> i32 {
+    2i32
+}
+
+unsafe fn h() -> i32 {
+    2i32
+}
+
 fn main() {
     require_fn(f);
     require_fn(f as fn() -> i32);
+    require_fn(f as unsafe fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+    //~| ERROR: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(g);
+    require_fn(g as extern "C" fn() -> i32);
+    //~^ ERROR: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+    //~| ERROR: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+    require_fn(h);
 }
diff --git a/tests/ui/traits/new-solver/fn-trait.stderr b/tests/ui/traits/new-solver/fn-trait.stderr
new file mode 100644
index 00000000000..01f1b64be20
--- /dev/null
+++ b/tests/ui/traits/new-solver/fn-trait.stderr
@@ -0,0 +1,64 @@
+error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() -> i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `unsafe fn() -> i32`
+   = note: wrap the `unsafe fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<unsafe fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:20:16
+   |
+LL |     require_fn(f as unsafe fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() -> i32`
+  --> $DIR/fn-trait.rs:24:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an `Fn<()>` closure, found `extern "C" fn() -> i32`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Fn<()>` is not implemented for `extern "C" fn() -> i32`
+   = note: wrap the `extern "C" fn() -> i32` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:23
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                       ^^^^^^^^^^^ required by this bound in `require_fn`
+
+error[E0271]: type mismatch resolving `<extern "C" fn() -> i32 as FnOnce<()>>::Output == i32`
+  --> $DIR/fn-trait.rs:24:16
+   |
+LL |     require_fn(g as extern "C" fn() -> i32);
+   |     ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `require_fn`
+  --> $DIR/fn-trait.rs:3:31
+   |
+LL | fn require_fn(_: impl Fn() -> i32) {}
+   |                               ^^^ required by this bound in `require_fn`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.