-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Change desugaring of let-else to ensure temporary is dropped earlier #94012
Conversation
This comment has been minimized.
This comment has been minimized.
Ah, well that puts a stopper in that idea. If the trailing statements are divergent, then the // orig
let Some(x) = blah() else {
return;
};
loop {}
// desugar
let val = if let Some(x) = blah() {
loop {}
} else {
return;
};
val // unreachable |
Unless it's feasible to programmatically add an |
8ba5ee9
to
29d3914
Compare
This prevents *any* unreachable_code warnings on DropTemps, including from its other uses.
29d3914
to
07539b8
Compare
Thanks to @camsteffen this now uses DropTemps as it should. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the fix looks good, but I still don't understand why we actually first drop locals and then temporaries in the first place. Would like to figure this out before merging this pr. currently looking into this.
+ remove actual unused vars from some other tests to be less distracting
👍 Let us know what you find out, it is a bit of a mystery to me too. |
Got another idea. Perhaps we can lower to |
The generated if-let is a tail position expression that needs to function as an implicit return value. It's got to be an Expr. |
Why? A let-else statement is even written as a statement with a semicolon. |
Look for yourself with {
let Ok(s) = expr else {
return 0;
};
// many statements
5
} // end of block
// desugars into
{
if let Ok(s) = expr {
// many statements
5
} else {
return 0;
}
} // end of block The result is an implicit return expression of type integer. |
Oh yeah 🤦 don't mind me! |
here's an example that would break if we were to first drop locals and then temporaries struct DropsA<'a>(&'a str);
impl DropsA<'_> {
fn as_unit(&self) {}
}
impl Drop for DropsA<'_> {
fn drop(&mut self) {}
}
fn main() {
let mut slot = None;
drop(slot.replace(DropsA(&String::from("Hey"))))
} after #94012 (comment) r=me |
@bors r+ |
📌 Commit d549ede has been approved by |
@bors rollup=never probably fine, but considering how frequently |
Thanks @lcnr, that makes sense. Also, whoa, I did not know we were up to 381 uses in |
☔ The latest upstream changes (presumably #94254) made this pull request unmergeable. Please resolve the merge conflicts. |
@@ -159,6 +159,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | |||
span, | |||
kind: hir::ExprKind::If(let_expr, then_expr, Some(else_expr)), | |||
}); | |||
let drop_temps = self.expr_drop_temps(span, if_expr, AttrVec::new()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be consistent with let
we would have to actually drop temps for the let_expr
or init_expr
, wouldn't we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, gut feeling this would fix the new problem. Good idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imagine the most straightforward solution will drop temps before the else
block instead of after it. Maybe that's okay, but just want to make sure that detail is considered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My proposed fix does not fix the general discrepancy between let and let-else, e.g https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=57e814fa57019bc62930bc9d61c894da
after the last lang meeting either @nikomatsakis or @pnkfelix should take over the review here. i am not familar enough with rusts temporary rules
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should a new issue be filed? Or work it within this issue
🔒 Merge conflict This pull request and the master branch diverged in a way that cannot be automatically merged. Please rebase on top of the latest master branch, and let the reviewer approve again. How do I rebase?Assuming
You may also read Git Rebasing to Resolve Conflicts by Drew Blessing for a short tutorial. Please avoid the "Resolve conflicts" button on GitHub. It uses Sometimes step 4 will complete without asking for resolution. This is usually due to difference between how Error message
|
1 similar comment
🔒 Merge conflict This pull request and the master branch diverged in a way that cannot be automatically merged. Please rebase on top of the latest master branch, and let the reviewer approve again. How do I rebase?Assuming
You may also read Git Rebasing to Resolve Conflicts by Drew Blessing for a short tutorial. Please avoid the "Resolve conflicts" button on GitHub. It uses Sometimes step 4 will complete without asking for resolution. This is usually due to difference between how Error message
|
@rustbot claim I'm taking over review here for now. |
🔒 Merge conflict This pull request and the master branch diverged in a way that cannot be automatically merged. Please rebase on top of the latest master branch, and let the reviewer approve again. How do I rebase?Assuming
You may also read Git Rebasing to Resolve Conflicts by Drew Blessing for a short tutorial. Please avoid the "Resolve conflicts" button on GitHub. It uses Sometimes step 4 will complete without asking for resolution. This is usually due to difference between how Error message
|
Ping from triage: FYI: when a PR is ready for review, send a message containing |
@cormacrelf I am currently planning to look into approaches for fixing this more generally with @dingxiangfei2009 . Would you like to try to collaborate with us as well on that? Do you think we should close this PR, or try to adapt it? |
|
🔒 Merge conflict This pull request and the master branch diverged in a way that cannot be automatically merged. Please rebase on top of the latest master branch, and let the reviewer approve again. How do I rebase?Assuming
You may also read Git Rebasing to Resolve Conflicts by Drew Blessing for a short tutorial. Please avoid the "Resolve conflicts" button on GitHub. It uses Sometimes step 4 will complete without asking for resolution. This is usually due to difference between how Error message
|
Thanks for looping me in. Yeah, I didn't push for the DropTemps, not being all that confident of its prospects after the case @lcnr found in that last review comment. Should have cleared it up, I will take one last look and close. The notes are good, I think the chosen course seems about right. I'll be happy to lend a hand, tag me if you want me to take a look at anything as I'm reasonably familiar with this code (although I'll be no use with THIR). From my experience with it, tweaking HIR is a bit of a slog getting it to compile all the way through, so commit early & regularly go outside to look at a dog or a cloud or something, is my free advice if you want it @dingxiangfei2009. |
ping from triage: FYI: when a PR is ready for review, send a message containing |
Fixes #98672 (Just for the record. I think this may be closed in favor of a different approach?) |
…=Mark-Simulacrum Add two let else regression tests Adds a regression test for rust-lang#94176, as it was fixed by rust-lang#98574 but doesn't have a regression test. The PR also incorporates a commit from rust-lang#94012 which added a test for an issue discovered in that PR. Originally they have been part of rust-lang#99291, but I've moved them out in the hopes of getting them merged more quickly, as that PR is already open since a month, and so that rust-lang#99291 can focus on the drop order part of things. Closes rust-lang#94176 Closes rust-lang#96961 -- dupe of rust-lang#94176
Fixes #93951. Ref #87335. Now uses DropTemps per Cam's suggestion, which is equivalent to what I was doing earlier but obviously much better and now only a 3-line change.
This new desugaring introduces a named temporary to hold the result of evaluating the generated if-let. The named temporary surrounding the whole if-let allows borrowck to see that the unnamed temporary that holdsfoo(&x)
is dropped beforex
is. I think in rustc terminology you can say there is now a destruction scope betweenfoo(&x)
and the}
wherex
is dropped.An alternative would be to introduce even finer-grained scopes in implicit return expressions. But that seems a much bigger change, and much more difficult for me. Or, of course, go back to the original strategy of extracting the pattern's bindings via a tuple.From here:
r? @lcnr