Skip to content

Rust attemts to implement FnMut for a closure consuming a 'static mut reference? #104837

Open
@rMazeiks

Description

@rMazeiks

Consider the following code:

struct Foo();

fn bar(foo_ref: &'static mut Foo) {
    let mut c = move || {
        foo(foo_ref);
    };
    c();
}

fn foo(foo_ref: &'static mut Foo) {}

fn main() {}

It fails to compile on both nightly and stable:

error: lifetime may not live long enough
 --> src/main.rs:5:9
  |
4 |     let mut c = move || {
  |                 ------- lifetime `'1` represents this closure's body
5 |         foo(foo_ref);
  |         ^^^^^^^^^^^^ argument requires that `'1` must outlive `'static`
  |
  = note: closure implements `FnMut`, so references to captured variables can't escape the closure

If I'm reading the error correctly, this is because Rust tries to implement FnMut for the closure. However, since the closure consumes the &'static mut Foo, it can only implement FnOnce. Indeed, I can "manually" create such a closure on nightly:

#![feature(unboxed_closures)]
#![feature(fn_traits)]

struct Foo();

fn bar(foo_ref: &'static mut Foo) {
    let c = ManualClosure { foo_ref };
    c();
}

fn foo(foo_ref: &'static mut Foo) {}

struct ManualClosure {
    foo_ref: &'static mut Foo,
}

impl FnOnce<()> for ManualClosure {
    type Output = ();

    extern "rust-call" fn call_once(self, args: ()) -> Self::Output {
        foo(self.foo_ref);
    }
}

I would expect the original code to work pretty much the same, with c being FnOnce but not FnMut. Is this a bug?

(Original (slightly cursed) question on Mastodon)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-closuresArea: Closures (`|…| { … }`)A-inferenceArea: Type inference

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions