From d9d97c4e76570bd79848ae13fe1f3851a2ceeeef Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 29 Jul 2026 19:12:43 -0400 Subject: [PATCH] Implement `Fn` traits for functions of any ABI This brings the behavior of the language in line with the documentation in `library/core/src/primitive_docs.rs`. --- compiler/rustc_abi/src/extern_abi.rs | 37 ++++++++++++++ .../src/error_reporting/traits/suggestions.rs | 5 +- compiler/rustc_type_ir/src/ty_kind.rs | 2 +- src/tools/miri/tests/pass/fn-traits-abi.rs | 39 +++++++++++++++ .../async-closures/fn-exception.rs | 2 +- .../async-closures/fn-exception.stderr | 16 +------ tests/ui/extern/extern-wrong-value-type.rs | 8 ++-- .../ui/extern/extern-wrong-value-type.stderr | 19 -------- .../suggest-option-asderef-unfixable.rs | 12 ++--- .../suggest-option-asderef-unfixable.stderr | 48 ++++++++----------- tests/ui/traits/next-solver/fn-trait.rs | 2 - tests/ui/traits/next-solver/fn-trait.stderr | 36 +------------- .../unboxed-closures/unboxed-closures-abi.rs | 40 ++++++++++++++++ .../unboxed-closures-wrong-abi.rs | 34 ------------- .../unboxed-closures-wrong-abi.stderr | 48 ------------------- 15 files changed, 150 insertions(+), 198 deletions(-) create mode 100644 src/tools/miri/tests/pass/fn-traits-abi.rs delete mode 100644 tests/ui/extern/extern-wrong-value-type.stderr create mode 100644 tests/ui/unboxed-closures/unboxed-closures-abi.rs delete mode 100644 tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs delete mode 100644 tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 79cee81d0fa2d..91c0bc0b59bca 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -369,6 +369,43 @@ impl ExternAbi { | Self::Swift => true, } } + + /// Returns whether safe functions with this ABI implement the `Fn` traits. + /// `false` only for uncallable or internal ABIs. + pub fn is_fn_trait_compatible(self) -> bool { + match self { + ExternAbi::C { .. } + | ExternAbi::System { .. } + | ExternAbi::Rust + | ExternAbi::RustCold + | ExternAbi::RustPreserveNone + | ExternAbi::RustTail + | ExternAbi::EfiApi + | ExternAbi::Swift + | ExternAbi::Aapcs { .. } + | ExternAbi::CmseNonSecureCall + | ExternAbi::CmseNonSecureEntry + | ExternAbi::Cdecl { .. } + | ExternAbi::Stdcall { .. } + | ExternAbi::Fastcall { .. } + | ExternAbi::Thiscall { .. } + | ExternAbi::Vectorcall { .. } + | ExternAbi::SysV64 { .. } + | ExternAbi::Win64 { .. } => true, + ExternAbi::RustCall + | ExternAbi::RustInvalid + | ExternAbi::LlvmIntrinsic + | ExternAbi::Custom + | ExternAbi::GpuKernel + | ExternAbi::PtxKernel + | ExternAbi::AvrInterrupt + | ExternAbi::AvrNonBlockingInterrupt + | ExternAbi::Msp430Interrupt + | ExternAbi::RiscvInterruptM + | ExternAbi::RiscvInterruptS + | ExternAbi::X86Interrupt => false, + } + } } pub fn all_names() -> Vec<&'static str> { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 32237e9f60ca3..f2471dec51f41 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5,7 +5,6 @@ use std::path::PathBuf; use std::{debug_assert_matches, iter}; use itertools::{EitherOrBoth, Itertools}; -use rustc_abi::ExternAbi; use rustc_attr_ir::lang_items::{self, LangItem}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; @@ -5490,9 +5489,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .. } = fn_ty.fn_sig(tcx).skip_binder() // FIXME(splat): this might need to change if the Fn* traits start using/supporting splat - && fn_sig.abi() == ExternAbi::Rust - && !fn_sig.c_variadic() - && fn_sig.safety() == hir::Safety::Safe + && fn_sig.is_fn_trait_compatible() // Extract first param of fn sig with peeled refs, e.g. `fn(&T)` -> `T` && let Some(&ty::Ref(_, target_ty, needs_mut)) = fn_sig.inputs().first().map(|t| t.kind()) diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 68a1b479830e2..eeea8506c9c73 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -1145,7 +1145,7 @@ impl FnSig { } pub fn is_fn_trait_compatible(self) -> bool { - !self.c_variadic() && self.safety().is_safe() && self.abi() == ExternAbi::Rust + !self.c_variadic() && self.safety().is_safe() && self.abi().is_fn_trait_compatible() } /// Set the safety flag. diff --git a/src/tools/miri/tests/pass/fn-traits-abi.rs b/src/tools/miri/tests/pass/fn-traits-abi.rs new file mode 100644 index 0000000000000..ed2579f7ab529 --- /dev/null +++ b/src/tools/miri/tests/pass/fn-traits-abi.rs @@ -0,0 +1,39 @@ +//! Test implementation of `Fn` traits for functions with non-`Rust` ABI + +use std::ops::{Fn, FnMut, FnOnce}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct Foo(i32, i32); + +extern "C" fn square(foo: Foo) -> Foo { + Foo(foo.0 * foo.1, foo.0 - foo.1) +} + +fn call_it Foo>(f: &F, i: Foo) -> Foo { + f(i) +} + +fn call_it_mut Foo>(f: &mut F, i: Foo) -> Foo { + f(i) +} + +fn call_it_once Foo>(f: F, i: Foo) -> Foo { + f(i) +} + +fn main() { + assert_eq!(call_it(&square, Foo(20, 10)), Foo(200, 10)); + assert_eq!(call_it_mut(&mut square, Foo(21, 9)), Foo(189, 12)); + assert_eq!(call_it_once(square, Foo(18, -3)), Foo(-54, 21)); + + let mut square_ptr: extern "C" fn(Foo) -> Foo = square; + assert_eq!(call_it(&square_ptr, Foo(30, 11)), Foo(330, 19)); + assert_eq!(call_it_mut(&mut square_ptr, Foo(273, -1)), Foo(-273, 274)); + assert_eq!(call_it_once(square_ptr, Foo(27, 27)), Foo(729, 0)); + + let mut square_dyn: Box Foo> = Box::new(square); + assert_eq!(call_it(&*square_dyn, Foo(1, 3)), Foo(3, -2)); + assert_eq!(call_it_mut(&mut *square_dyn, Foo(5, 25)), Foo(125, -20)); + assert_eq!(call_it_once(square_dyn, Foo(9, 2)), Foo(18, 7)); +} diff --git a/tests/ui/async-await/async-closures/fn-exception.rs b/tests/ui/async-await/async-closures/fn-exception.rs index 8ff63983e7932..71df2178ff0c4 100644 --- a/tests/ui/async-await/async-closures/fn-exception.rs +++ b/tests/ui/async-await/async-closures/fn-exception.rs @@ -15,5 +15,5 @@ fn test(f: impl AsyncFn()) {} fn main() { test(unsafety); //~ ERROR the trait bound - test(abi); //~ ERROR the trait bound + test(abi); } diff --git a/tests/ui/async-await/async-closures/fn-exception.stderr b/tests/ui/async-await/async-closures/fn-exception.stderr index aa74ed234df00..a3366dda5ba73 100644 --- a/tests/ui/async-await/async-closures/fn-exception.stderr +++ b/tests/ui/async-await/async-closures/fn-exception.stderr @@ -12,20 +12,6 @@ note: required by a bound in `test` LL | fn test(f: impl AsyncFn()) {} | ^^^^^^^^^ required by this bound in `test` -error[E0277]: the trait bound `extern "C" fn() -> Pin + 'static)>> {abi}: AsyncFn()` is not satisfied - --> $DIR/fn-exception.rs:18:10 - | -LL | test(abi); - | ---- ^^^ the trait `AsyncFn()` is not implemented for fn item `extern "C" fn() -> Pin + 'static)>> {abi}` - | | - | required by a bound introduced by this call - | -note: required by a bound in `test` - --> $DIR/fn-exception.rs:14:17 - | -LL | fn test(f: impl AsyncFn()) {} - | ^^^^^^^^^ required by this bound in `test` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/extern/extern-wrong-value-type.rs b/tests/ui/extern/extern-wrong-value-type.rs index ae07a721e83ee..3aa3539777cad 100644 --- a/tests/ui/extern/extern-wrong-value-type.rs +++ b/tests/ui/extern/extern-wrong-value-type.rs @@ -1,11 +1,13 @@ +//@ run-pass + extern "C" fn f() { } -fn is_fn(_: F) where F: Fn() {} +fn is_fn(f: F) where F: Fn() { + f(); +} fn main() { - // extern functions are extern "C" fn let _x: extern "C" fn() = f; // OK is_fn(f); - //~^ ERROR expected an `Fn()` closure, found `extern "C" fn() {f}` } diff --git a/tests/ui/extern/extern-wrong-value-type.stderr b/tests/ui/extern/extern-wrong-value-type.stderr deleted file mode 100644 index e1686f8a3ab9b..0000000000000 --- a/tests/ui/extern/extern-wrong-value-type.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: expected an `Fn()` closure, found `extern "C" fn() {f}` - --> $DIR/extern-wrong-value-type.rs:9:11 - | -LL | is_fn(f); - | ----- ^ expected an `Fn()` closure, found `extern "C" fn() {f}` - | | - | required by a bound introduced by this call - | - = help: the trait `Fn()` is not implemented for fn item `extern "C" fn() {f}` - = note: wrap the `extern "C" fn() {f}` in a closure with no arguments: `|| { /* code */ }` -note: required by a bound in `is_fn` - --> $DIR/extern-wrong-value-type.rs:4:28 - | -LL | fn is_fn(_: F) where F: Fn() {} - | ^^^^ required by this bound in `is_fn` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs index 445a98cd49630..1fcb41e256d48 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs @@ -2,7 +2,7 @@ fn produces_string() -> Option { Some("my cool string".to_owned()) } -fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { +fn takes_str_but_too_many_refs(_: &str) -> Option<()> { Some(()) } @@ -10,11 +10,7 @@ fn no_args() -> Option<()> { Some(()) } -extern "C" fn takes_str_but_wrong_abi(_: &str) -> Option<()> { - Some(()) -} - -unsafe fn takes_str_but_unsafe(_: &str) -> Option<()> { +unsafe fn takes_str_but_unsafe(_: String) -> Option<()> { Some(()) } @@ -23,10 +19,8 @@ struct TypeWithoutDeref; fn main() { let _ = produces_string().and_then(takes_str_but_too_many_refs); //~^ ERROR type mismatch in function arguments - let _ = produces_string().and_then(takes_str_but_wrong_abi); - //~^ ERROR expected an `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` let _ = produces_string().and_then(takes_str_but_unsafe); - //~^ ERROR expected an `FnOnce(String)` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + //~^ ERROR expected an `FnOnce(String)` closure, found `unsafe fn(String) -> Option<()> {takes_str_but_unsafe}` let _ = produces_string().and_then(no_args); //~^ ERROR function is expected to take 1 argument, but it takes 0 arguments let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr index 14c821b260299..4c1b0bec4d745 100644 --- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr +++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr @@ -1,8 +1,8 @@ error[E0631]: type mismatch in function arguments - --> $DIR/suggest-option-asderef-unfixable.rs:24:40 + --> $DIR/suggest-option-asderef-unfixable.rs:20:40 | -LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { - | ------------------------------------------------------ found signature defined here +LL | fn takes_str_but_too_many_refs(_: &str) -> Option<()> { + | ----------------------------------------------------- found signature defined here ... LL | let _ = produces_string().and_then(takes_str_but_too_many_refs); | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this @@ -10,41 +10,33 @@ LL | let _ = produces_string().and_then(takes_str_but_too_many_refs); | required by a bound introduced by this call | = note: expected function signature `fn(String) -> _` - found function signature `fn(&&str) -> _` + found function signature `fn(&str) -> _` note: required by a bound in `Option::::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL help: consider wrapping the function in a closure | -LL | let _ = produces_string().and_then(|arg0: String| takes_str_but_too_many_refs(/* &&str */)); - | ++++++++++++++ +++++++++++++ - -error[E0277]: expected an `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` - --> $DIR/suggest-option-asderef-unfixable.rs:26:40 - | -LL | let _ = produces_string().and_then(takes_str_but_wrong_abi); - | -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce(String)` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` - | | - | required by a bound introduced by this call +LL | let _ = produces_string().and_then(|arg0: String| takes_str_but_too_many_refs(/* &str */)); + | ++++++++++++++ ++++++++++++ +help: call `Option::as_deref()` first | - = help: the trait `FnOnce(String)` is not implemented for fn item `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}` -note: required by a bound in `Option::::and_then` - --> $SRC_DIR/core/src/option.rs:LL:COL +LL | let _ = produces_string().as_deref().and_then(takes_str_but_too_many_refs); + | +++++++++++ -error[E0277]: expected an `FnOnce(String)` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` - --> $DIR/suggest-option-asderef-unfixable.rs:28:40 +error[E0277]: expected an `FnOnce(String)` closure, found `unsafe fn(String) -> Option<()> {takes_str_but_unsafe}` + --> $DIR/suggest-option-asderef-unfixable.rs:22:40 | LL | let _ = produces_string().and_then(takes_str_but_unsafe); | -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` | | | required by a bound introduced by this call | - = help: the trait `FnOnce(String)` is not implemented for fn item `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}` + = help: the trait `FnOnce(String)` is not implemented for fn item `unsafe fn(String) -> Option<()> {takes_str_but_unsafe}` = note: unsafe function cannot be called generically without an unsafe block note: required by a bound in `Option::::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL error[E0593]: function is expected to take 1 argument, but it takes 0 arguments - --> $DIR/suggest-option-asderef-unfixable.rs:30:40 + --> $DIR/suggest-option-asderef-unfixable.rs:24:40 | LL | fn no_args() -> Option<()> { | -------------------------- takes 0 arguments @@ -58,10 +50,10 @@ note: required by a bound in `Option::::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL error[E0631]: type mismatch in function arguments - --> $DIR/suggest-option-asderef-unfixable.rs:32:45 + --> $DIR/suggest-option-asderef-unfixable.rs:26:45 | -LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> { - | ------------------------------------------------------ found signature defined here +LL | fn takes_str_but_too_many_refs(_: &str) -> Option<()> { + | ----------------------------------------------------- found signature defined here ... LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected due to this @@ -69,15 +61,15 @@ LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs); | required by a bound introduced by this call | = note: expected function signature `fn(TypeWithoutDeref) -> _` - found function signature `fn(&&str) -> _` + found function signature `fn(&str) -> _` note: required by a bound in `Option::::and_then` --> $SRC_DIR/core/src/option.rs:LL:COL help: consider wrapping the function in a closure | -LL | let _ = Some(TypeWithoutDeref).and_then(|arg0: TypeWithoutDeref| takes_str_but_too_many_refs(/* &&str */)); - | ++++++++++++++++++++++++ +++++++++++++ +LL | let _ = Some(TypeWithoutDeref).and_then(|arg0: TypeWithoutDeref| takes_str_but_too_many_refs(/* &str */)); + | ++++++++++++++++++++++++ ++++++++++++ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0593, E0631. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/fn-trait.rs b/tests/ui/traits/next-solver/fn-trait.rs index e31d4d2b580a5..de9841089b7e9 100644 --- a/tests/ui/traits/next-solver/fn-trait.rs +++ b/tests/ui/traits/next-solver/fn-trait.rs @@ -20,9 +20,7 @@ fn main() { require_fn(f as unsafe fn() -> i32); //~^ ERROR: expected an `Fn()` closure, found `unsafe fn() -> i32` require_fn(g); - //~^ ERROR: expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` require_fn(g as extern "C" fn() -> i32); - //~^ ERROR: expected an `Fn()` closure, found `extern "C" fn() -> i32` require_fn(h); //~^ ERROR: expected an `Fn()` closure, found `unsafe fn() -> i32 {h}` } diff --git a/tests/ui/traits/next-solver/fn-trait.stderr b/tests/ui/traits/next-solver/fn-trait.stderr index 6218928b309f7..65bad29a67751 100644 --- a/tests/ui/traits/next-solver/fn-trait.stderr +++ b/tests/ui/traits/next-solver/fn-trait.stderr @@ -15,40 +15,8 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error[E0277]: expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` - --> $DIR/fn-trait.rs:22:16 - | -LL | require_fn(g); - | ---------- ^ expected an `Fn()` closure, found `extern "C" fn() -> i32 {g}` - | | - | required by a bound introduced by this call - | - = help: the trait `Fn()` is not implemented for fn item `extern "C" fn() -> i32 {g}` - = note: wrap the `extern "C" fn() -> i32 {g}` 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[E0277]: expected an `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[E0277]: expected an `Fn()` closure, found `unsafe fn() -> i32 {h}` - --> $DIR/fn-trait.rs:26:16 + --> $DIR/fn-trait.rs:24:16 | LL | require_fn(h); | ---------- ^ call the function in a closure: `|| unsafe { /* code */ }` @@ -64,6 +32,6 @@ note: required by a bound in `require_fn` LL | fn require_fn(_: impl Fn() -> i32) {} | ^^^^^^^^^^^ required by this bound in `require_fn` -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/unboxed-closures/unboxed-closures-abi.rs b/tests/ui/unboxed-closures/unboxed-closures-abi.rs new file mode 100644 index 0000000000000..5aabc12971e63 --- /dev/null +++ b/tests/ui/unboxed-closures/unboxed-closures-abi.rs @@ -0,0 +1,40 @@ +//@ run-pass +//! Test implementation of `Fn` traits for functions with non-`Rust` ABI + +use std::ops::{Fn, FnMut, FnOnce}; + +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +struct Foo(i32, i32); + +extern "C" fn square(foo: Foo) -> Foo { + Foo(foo.0 * foo.1, foo.0 - foo.1) +} + +fn call_it Foo>(f: &F, i: Foo) -> Foo { + f(i) +} + +fn call_it_mut Foo>(f: &mut F, i: Foo) -> Foo { + f(i) +} + +fn call_it_once Foo>(f: F, i: Foo) -> Foo { + f(i) +} + +fn main() { + assert_eq!(call_it(&square, Foo(20, 10)), Foo(200, 10)); + assert_eq!(call_it_mut(&mut square, Foo(21, 9)), Foo(189, 12)); + assert_eq!(call_it_once(square, Foo(18, -3)), Foo(-54, 21)); + + let mut square_ptr: extern "C" fn(Foo) -> Foo = square; + assert_eq!(call_it(&square_ptr, Foo(30, 11)), Foo(330, 19)); + assert_eq!(call_it_mut(&mut square_ptr, Foo(273, -1)), Foo(-273, 274)); + assert_eq!(call_it_once(square_ptr, Foo(27, 27)), Foo(729, 0)); + + let mut square_dyn: Box Foo> = Box::new(square); + assert_eq!(call_it(&*square_dyn, Foo(1, 3)), Foo(3, -2)); + assert_eq!(call_it_mut(&mut *square_dyn, Foo(5, 25)), Foo(125, -20)); + assert_eq!(call_it_once(square_dyn, Foo(9, 2)), Foo(18, 7)); +} diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs deleted file mode 100644 index dd76c597d28ad..0000000000000 --- a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Tests that unsafe extern fn pointers do not implement any Fn traits. - -use std::ops::{Fn, FnMut, FnOnce}; - -extern "C" fn square(x: &isize) -> isize { - (*x) * (*x) -} - -fn call_it isize>(_: &F, _: isize) -> isize { - 0 -} -fn call_it_mut isize>(_: &mut F, _: isize) -> isize { - 0 -} -fn call_it_once isize>(_: F, _: isize) -> isize { - 0 -} - -fn a() { - let x = call_it(&square, 22); - //~^ ERROR E0277 -} - -fn b() { - let y = call_it_mut(&mut square, 22); - //~^ ERROR E0277 -} - -fn c() { - let z = call_it_once(square, 22); - //~^ ERROR E0277 -} - -fn main() {} diff --git a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr deleted file mode 100644 index 25cf793ca00e8..0000000000000 --- a/tests/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error[E0277]: expected an `Fn(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:20:21 - | -LL | let x = call_it(&square, 22); - | ------- ^^^^^^^ expected an `Fn(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - | | - | required by a bound introduced by this call - | - = help: the trait `for<'a> Fn(&'a isize)` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` -note: required by a bound in `call_it` - --> $DIR/unboxed-closures-wrong-abi.rs:9:15 - | -LL | fn call_it isize>(_: &F, _: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it` - -error[E0277]: expected an `FnMut(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:25:25 - | -LL | let y = call_it_mut(&mut square, 22); - | ----------- ^^^^^^^^^^^ expected an `FnMut(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - | | - | required by a bound introduced by this call - | - = help: the trait `for<'a> FnMut(&'a isize)` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` -note: required by a bound in `call_it_mut` - --> $DIR/unboxed-closures-wrong-abi.rs:12:19 - | -LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_mut` - -error[E0277]: expected an `FnOnce(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - --> $DIR/unboxed-closures-wrong-abi.rs:30:26 - | -LL | let z = call_it_once(square, 22); - | ------------ ^^^^^^ expected an `FnOnce(&isize)` closure, found `for<'a> extern "C" fn(&'a isize) -> isize {square}` - | | - | required by a bound introduced by this call - | - = help: the trait `for<'a> FnOnce(&'a isize)` is not implemented for fn item `for<'a> extern "C" fn(&'a isize) -> isize {square}` -note: required by a bound in `call_it_once` - --> $DIR/unboxed-closures-wrong-abi.rs:15:20 - | -LL | fn call_it_once isize>(_: F, _: isize) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `call_it_once` - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0277`.