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

Replacing a parameter declared as mut a with let mut a = a; causes program to no longer compile #31723

Closed
bstrie opened this issue Feb 17, 2016 · 5 comments
Labels
A-destructors Area: destructors (Drop, ..)

Comments

@bstrie
Copy link
Contributor

bstrie commented Feb 17, 2016

This may very well be a dupe of #31439, but it manifests somewhat differently and may shed light on the potential fix. Probably still worth having a test case for anyway.

Take this program, which compiles:

fn test_drain(mut a: Vec<u32>) -> Vec<u32> {
    a.drain(..).collect::<Vec<u32>>()
}

fn main() {}

Now, instead of declaring the parameter as mut a, declare it as immutable and rebind it as mutable in the body of the function, which is supposed to be semantically equivalent. This results in a compiler error:

fn test_drain(a: Vec<u32>) -> Vec<u32> {
    let mut a = a;
    a.drain(..).collect::<Vec<u32>>()
}

fn main() {}
<anon>:3:5: 3:6 error: `a` does not live long enough
<anon>:3     a.drain(..).collect::<Vec<u32>>()
             ^
<anon>:1:40: 4:2 note: reference must be valid for the destruction scope surrounding block at 1:39...
<anon>:1 fn test_drain(a: Vec<u32>) -> Vec<u32> {
<anon>:2     let mut a = a;
<anon>:3     a.drain(..).collect::<Vec<u32>>()
<anon>:4 }
<anon>:2:19: 4:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 2:18
<anon>:2     let mut a = a;
<anon>:3     a.drain(..).collect::<Vec<u32>>()
<anon>:4 }
error: aborting due to previous error
playpen: application terminated with error code 101

As in #31439, replacing the implicit return with an explicit return also allows the program to compile.

@arielb1
Copy link
Contributor

arielb1 commented Feb 17, 2016

This is the destruction order problem: the destructor of Vec runs before the destructor of drain, so if collect panics you will have trouble.

@Thiez
Copy link
Contributor

Thiez commented Feb 18, 2016

@arielb1 I was under the impression that destructors ran in reverse order of declaration, so surely the destructor of drain would in fact run before the destructor of Vec?

@pnkfelix
Copy link
Member

I would need to go review the temp r-value lifetime rules in a case like this, in terms of how the temporaries of the final expression in a block relate to the local variables in that block

(I know it's unintuitive for explicit return to work in cases like this that are supposedly equivalent ...)

@Thiez
Copy link
Contributor

Thiez commented Feb 18, 2016

@pnkfelix If/when you review those rules, could you perhaps check whether the root cause is the same as the example here?

@Mark-Simulacrum
Copy link
Member

Closing in favor of #21114. Please reopen if that's incorrect, but from what I can tell this is a duplicate of that issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-destructors Area: destructors (Drop, ..)
Projects
None yet
Development

No branches or pull requests

5 participants