Code change:
<ins> error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:24:10 | LL | fn call(f: impl Fn()) { |                 ---- required by this bound in `call` ... LL |     call(foo); |          ^^^ expected an `Fn<()>` closure, found `fn() {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: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:25:14 | LL | fn call_mut(f: impl FnMut()) { |                     ------- required by this bound in `call_mut` ... LL |     call_mut(foo); |              ^^^ expected an `FnMut<()>` closure, found `fn() {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: `#[target_feature]` functions do not implement the `Fn` traits error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:26:15 | LL | fn call_once(f: impl FnOnce()) { |                      -------- required by this bound in `call_once` ... LL |     call_once(foo); |               ^^^ expected an `FnOnce<()>` closure, found `fn() {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: `#[target_feature]` functions do not implement the `Fn` traits 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 */ } = note: `#[target_feature]` functions do not implement the `Fn` traits 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 */ } = note: `#[target_feature]` functions do not implement the `Fn` traits 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 */ } = note: `#[target_feature]` functions do not implement the `Fn` traits error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. </ins>

Related discussion:
text: The "unsafety checker enhancement" should only affect unsafe functions that are made unsafe through , but not other means (explicit or block).
I'm new to the compiler, but it seemed non-trivial to change functions to unsafe when lowering to HIR. It looks to me like you'd end up with just as many exceptions (ignoring the unsafe in some scenarios), in addition tracking the origin of the . On the other hand it was pretty trivial to not implement the Fn traits instead. I'll open a PR with my fix, but please close it if the other method is preferred.
So there are sort of two questions here. One of them is what user-visible behavior is permitted, and the other is how precisely that is implemented in the compiler. I think the latter only concerns the team in-so-far as it represents the impact on the language spec and on the "mental model" that users must keep in mind. Nominating for the lang-team meeting to discuss solution, which is simply to make "target-feature" functions not implement the traits (just as functions do not implement the traits, along with functions with non-Rust ABIs etc).
I think I was tagged by mistake :wink:
Apologies! Fixed. Github autocompleted that for me. Here I was feeling so grateful to it.
We discussed this in . The conclusion was that the fix that proposed is good for right now. It's already the case that many items do not implement the function trait (e.g., those with custom ABIs or which are unsafe), so this would be "yet another" case (admittedly a somewhat different one in that this case doesn't show up in the type of function pointers, for better or worse). We uncovered a few other interesting observations: pointed out that their ideal preference would be to have something like " only implements " within an unsafe block, but of course the trait system has no precedent for that. It would be sort of like a attached to the impl block (i.e., the impl is usable in some context where unsafe code is allowed). Another possibility might be " only implements within a fn that has a suitable target feature in scope". This is an interesting idea because, although the pointer could escape in the form of a , the idea is that once you enter , you've already demonstrated that you possess the target feature, so it's ok if the value escapes.