rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

Lifetime error returning a tuple, one value referencing the other

Open aaron-jack-manning opened this issue 3 years ago • 3 comments

Consider the following block of code:

struct Foo<'a> {
    bar : &'a Bar
}

struct Bar {}

fn test<'a>() -> (Bar, Foo<'a>) {
    let bar = Bar {};
    let foo = Foo { bar : &bar };

    (bar, foo)
}

fn main() {
    let (bar, foo) = test();
}

which gives the following error:

error[E0515]: cannot return value referencing local variable `bar`
  --> main.rs:11:5
   |
9  |     let foo = Foo { bar : &bar };
   |                           ---- `bar` is borrowed here
10 | 
11 |     (bar, foo)
   |     ^^^^^^^^^^ returns a value referencing data owned by the current function

However the tuple returns the two values together, one of which contains a reference to the other. The compiler should be able to identify that the ownership of bar is transferred out of the function alongside the reference to it.

aaron-jack-manning avatar Jun 27 '22 10:06 aaron-jack-manning

I believe the answer is the following.

You’re correct that ownership of bar is transferred to the outside of the function. However, the problem is that bar is created on the stack inside test. Thus, a reference to it is a reference to something on the stack area of test. When test returns, that part of the stack ceases to exist and bar is moved to the stack area of main. So the location of bar changes in memory and the reference you’re returning in the tuple is no longer valid after the return of test.

truppelito avatar Jun 27 '22 11:06 truppelito

If this was meant to be a bug report, you shall have posted it to https://github.com/rust-lang/rust instead.

Aside from that, the compiler is correct as @truppelito has explained. You can look for crates such as owning_ref (warning: it is unsound).

ChayimFriedman2 avatar Jun 27 '22 15:06 ChayimFriedman2