Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lifetime error on methods that accept &mut self and return a borrow of self #1

Closed
saethlin opened this issue Nov 2, 2018 · 3 comments

Comments

@saethlin
Copy link

saethlin commented Nov 2, 2018

#[macro_use]
extern crate no_panic;

struct Foo {
    data: usize,
}

impl Foo {
    #[no_panic]
    fn get_mut(&mut self) -> &mut usize {
        &mut self.data
    }
}

fn main() {}

with NLLs I see this (the current borrow checker message is very verbose):

error: captured variable cannot escape `FnMut` closure body
  --> src/main.rs:12:9
   |
10 |     #[no_panic]
   |               - inferred to be a `FnMut` closure
11 |     fn get_mut(&mut self) -> &mut usize {
12 |         &mut self.data
   |         ^^^^^^^^^^^^^^ returns a reference to a captured variable which escapes the closure body
   |
   = note: `FnMut` closures only have access to their captured variables while they are executing...
   = note: ...therefore, they cannot allow references to captured variables to escape

And if change the return type to be a &usize, a slight variation on it

  --> src/main.rs:12:9
   |
10 |     #[no_panic]
   |     -----------
   |     |         |
   |     |         return type of closure is &'2 usize
   |     lifetime `'1` represents this closure's body
11 |     fn get_mut(&mut self) -> &usize {
12 |         &self.data
   |         ^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
   |
   = note: closure implements `Fn`, so references to captured variables can't escape the closure

To be honest, I'm at a loss to explain this. Everything is fine if the method accepts &self. Is this a limitation of the existing borrow checkers?

@saethlin saethlin changed the title Lifetime error on methods that accept &mut self Lifetime error on methods that accept &mut self and return a borrow of self Nov 2, 2018
@dtolnay
Copy link
Owner

dtolnay commented Nov 2, 2018

Seems like a borrow checker limitation! For now you can work around it by writing:

#[no_panic]
fn get_mut(&mut self) -> &mut usize {
    &mut {self}.data
}

I would love a PR to fix this.

@saethlin
Copy link
Author

saethlin commented Nov 2, 2018

Can you explain to me how that fix works? I think this is way beyond me.

@dtolnay
Copy link
Owner

dtolnay commented Nov 2, 2018

For move closures there appears to be a difference between reborrowing from the input reference, in which case the reborrow lives only as long as the closure, vs moving ownership of the original borrow into the closure, which lives as long as the input reference. Curly braces result in the value being moved rather than reborrowed.

struct S {
    data: usize,
}

fn does_not_compile(s: &mut S) -> &mut usize {
    (move || &mut s.data)()
}

fn ok(s: &mut S) -> &mut usize {
    (move || &mut {s}.data)()
}

#[no_panic] internally uses a move closure to insert a check just before the function returns for whether it is returning normally or unwinding from a panic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants