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

Implicit return leads to "does not live long enough" error. #31439

Closed
gyscos opened this issue Feb 6, 2016 · 6 comments
Closed

Implicit return leads to "does not live long enough" error. #31439

gyscos opened this issue Feb 6, 2016 · 6 comments
Labels
A-lifetimes Area: Lifetimes / regions T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@gyscos
Copy link

gyscos commented Feb 6, 2016

Here is a simple function that tries to read all lines from input:

use std::io::{self,BufRead};

fn lines() -> Vec<String> {
    let stdin = io::stdin();
    let handle = stdin.lock();

    handle.lines().map(|line| line.unwrap()).collect()
}

fn main() {
}

As shown here, attempting to compile it (on stable 1.6, beta or nightly) gives a lifetime error:

<anon>:5:18: 5:23 error: `stdin` does not live long enough
<anon>:5     let handle = stdin.lock();
                          ^~~~~
<anon>:3:27: 8:2 note: reference must be valid for the destruction scope surrounding block at 3:26...
<anon>:3 fn lines() -> Vec<String> {
<anon>:4     let stdin = io::stdin();
<anon>:5     let handle = stdin.lock();
<anon>:6 
<anon>:7     handle.lines().map(|line| line.unwrap()).collect()
<anon>:8 }
<anon>:4:29: 8:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:28
<anon>:4     let stdin = io::stdin();
<anon>:5     let handle = stdin.lock();
<anon>:6 
<anon>:7     handle.lines().map(|line| line.unwrap()).collect()
<anon>:8 }

Making the return explicit fixes this:

use std::io::{self,BufRead};

fn lines() -> Vec<String> {
    let stdin = io::stdin();
    let handle = stdin.lock();

    return handle.lines().map(|line| line.unwrap()).collect();
}

fn main() {
}

Is this the expected behavior? I would have thought explicit and implicit returns would give the same result...

@gyscos gyscos changed the title Implicit return confuses lifetime checker Implicit return leads to "does not live long enough" error. Feb 6, 2016
@steveklabnik
Copy link
Member

This does seem like a bug. I can't quite remember, but I think there is a similar issue somewhere...

@arielb1
Copy link
Contributor

arielb1 commented Feb 17, 2016

This looks like a destruction order problem to me.

@Thiez
Copy link
Contributor

Thiez commented Feb 18, 2016

Assigning the result to a local and then implicitly returning that local also solves this problem:

fn lines() -> Vec<String> {
    let stdin = io::stdin();
    let handle = stdin.lock();

    let result = handle.lines().map(|line| line.unwrap()).collect();
    result
}

Perhaps rustc sometimes incorrectly requires too many lifetimes in an implicit return expression to be valid until the end of the function, instead of looking only at the lifetimes mentioned in the result of the expression?

@Thiez
Copy link
Contributor

Thiez commented Feb 18, 2016

Here, a minimal example:

struct S{ n: u8 }
struct T<'a>{ s: &'a S }
impl<'a> Drop for T<'a> { fn drop(&mut self){} }

fn test_good() -> u8 { // this is fine
    let s = S{ n: 5 };
    return T{ s: &s }.s.n;
}

fn test_bad() -> u8 { // this is not
    let s = S{ n: 5 };
    T{ s: &s }.s.n
}

fn main(){}

@Ryman
Copy link
Contributor

Ryman commented May 9, 2016

Seems related to #22252

@arielb1
Copy link
Contributor

arielb1 commented May 24, 2016

This looks like a duplicate of #33490 - on MIR it would be a segfault.

@arielb1 arielb1 closed this as completed May 24, 2016
@steveklabnik steveklabnik added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Mar 24, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: Lifetimes / regions T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants