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

Explicitly describe temporary drop order difference between return expr; and final block expression #452

Closed
Havvy opened this issue Oct 16, 2018 · 2 comments · Fixed by #514
Assignees

Comments

@Havvy
Copy link
Contributor

Havvy commented Oct 16, 2018

Due to temporaries in the final expression of a block living longer than the block expression itself, there's actually a difference between a return expression and the final expression in a block. This should be explicitly documented so that we can link to people about it.

Associated Rust issue: rust-lang/rust#21114

@pnkfelix
Copy link
Member

pnkfelix commented Oct 30, 2018

Its probably worth expanding this issue to also cover the difference between { ...; EXPR } and { ...; let x = EXPR; x }.

(To which many might say "... there's a difference between those two?" Yes, and its similar to the difference cited in this issues title.)

For the start of a neat test for illustrating this, you might look at the tests I added related to rust-lang/rust#54556, such as https://github.com/rust-lang/rust/blob/master/src/test/ui/nll/issue-54556-stephaneyfx.rs. Its diagnostic output under NLL tries hard to explain what the issue is:

link:

error[E0597]: `stmt` does not live long enough
  --> $DIR/issue-54556-stephaneyfx.rs:27:21
   |
LL |     let rows = Rows(&stmt);
   |                     ^^^^^ borrowed value does not live long enough
LL |     rows.map(|row| row).next()
   |     ------------------- a temporary with access to the borrow is created here ...
...
LL | }
   | -
   | |
   | `stmt` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::iter::Map<Rows<'_>, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>`
   |
   = note: The temporary is part of an expression at the end of a block. Consider forcing this temporary to be dropped sooner, before the block's local variables are dropped. For example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block.

@pnkfelix
Copy link
Member

pnkfelix commented Nov 9, 2018

See also discussion here: rust-lang/rust#37612 which has examples where you get a deadlock because a temporary is surviving longer than the programmer expected, due to the these rules regarding the dynamic extent of temporaries.

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

Successfully merging a pull request may close this issue.

3 participants