Skip to content

let _ = foo() runs the destructor at the wrong time #16526

New issue

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

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

Already on GitHub? # to your account

Closed
nikomatsakis opened this issue Aug 15, 2014 · 6 comments
Closed

let _ = foo() runs the destructor at the wrong time #16526

nikomatsakis opened this issue Aug 15, 2014 · 6 comments

Comments

@nikomatsakis
Copy link
Contributor

I believe that the semantics of let _ = foo() should be that the destructor for the value returned by foo() runs at the end of the block. The reason for this is a consequence of a couple of other rules that I worked out as part of the temporary lifetime stuff.

In general, let <pat> = <rvalue> where <pat> is not a single identifier is equivalent to:

let _tmp = <rvalue>;
let <path> = _tmp;

In this case, that means that let _ = <rvalue> should be:

let _tmp = <rvalue>;
let _ = tmp;

and since the _ pattern just ignores the thing it matches against, this means that _tmp is unaffected and drops at the end of the block.

However, the following test case suggests that this is not what we do today:

struct Foo;

impl Drop for Foo {
    fn drop(&mut self) {
        println!("Hi2!");
    }
}

fn main() {
     let _ = Foo;
     println!("Hi1!");
}

This should print Hi1 and then Hi2 but in fact it prints the opposite. This is probably a hold-over from the special code that was in trans to special case the treatment of let _ vs other patterns, but I could be wrong.

cc @pcwalton @pnkfelix

@dotdash
Copy link
Contributor

dotdash commented Aug 16, 2014

This seems to originate from febd7ee.

cc @catamorphism

@dotdash
Copy link
Contributor

dotdash commented Aug 16, 2014

@nikomatsakis in #10488 you argued for the current behavior. Have semantics change since then so that the other behavior is preferable? Esp. regarding #10488 (comment) where you say that there's no equivalent and that it is an important capability.

@nikomatsakis
Copy link
Contributor Author

@dotdash I am saying that the current behavior does not reflect what I was arguing for and what I believe we agreed to.

@dotdash
Copy link
Contributor

dotdash commented Aug 18, 2014

If you treat let _ = foo() the same as

let _tmp = foo();
let _ = _tmp;

doesn't that mean that the value is actually bound? How does that fit with the "Don't bind it" semantics described in #10488? In fact code like that was given as an example for the "Bind it" semantics.

What am I missing?

@nikomatsakis
Copy link
Contributor Author

@dotdash at the time I wrote "this will depend on the precise temporary rules". What i'm saying is that the way we wound up defining the temporary rules, as I understand it, is supposed to mean that let _ = foo() lives as long as the entire block. Basically there are two independent things at play:

  1. what is the semantics of let <pat> = <rvalue> (regardless of what the pattern specifically is)
  2. what is the semantics of the _ pattern

@nikomatsakis
Copy link
Contributor Author

Actually, re-reading the code, I think I may be misremembering, and the current behavior is a logical outcome of the rules. That is, the lifetime of the temporary that is introduced is confined to the statement itself, because the pattern does not clearly take a ref.

matthiaskrgr pushed a commit to matthiaskrgr/rust that referenced this issue Feb 11, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants