-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Add tests for the drop behavior of some control flow constructs #100526
Conversation
(rust-highfive has picked a reviewer for you, use r? to override) |
In rust-lang#100513 it was shown that the drop behavior of let_chains is not correct currently. Since drop behavior is something pretty subtle, this adds explicit tests for the drop behavior of `if`, `if let` and `match` to make sure that it does not regress in the future. The `println!`s were left in to make debugging easier in case something goes wrong, but they are not required for the test.
@bors r+ rollup |
This is basically duplicating my PR #99291 which is more comprehensive (it might not be a true superset, need to check), but has still been open for a month without it being merged. I also think that my approach to use |
Ah, I wasn't aware about |
Sure, your solution works too. I am just a bit upset that my work was ignored. I'm not sure what I did wrong, but I'm happy that reviewers got around and accepted your PR. If this PR is merged, I might change #99291 to improve the added test. |
FWIW, I don't mind r+'ing #99291 if you think that's right, @est31 -- I missed #99291 (comment) previously. The reason I didn't re-assign this PR is that it didn't touch unstable constructs so seems obviously good, whereas #99291 is in a bit more of an interesting place where the expected semantics are intended to change. (But it also seems OK to test them in the meantime). I personally found this PR easier to review than the println!-based tests there, because I can directly see in one file what the expected order is (vs. comparing across two files). It also seems less likely to get missed in a rebase/large-scale stderr test update. |
…iaskrgr Rollup of 6 pull requests Successful merges: - rust-lang#100249 (Fix HorizonOS regression in FileTimes) - rust-lang#100253 (Recover from mutable variable declaration where `mut` is placed before `let`) - rust-lang#100482 (Add Duration rounding change to release note) - rust-lang#100523 ([rustdoc] remove Clean trait) - rust-lang#100524 (Impl `Debug` for some structs of rustbuild) - rust-lang#100526 (Add tests for the drop behavior of some control flow constructs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
@Mark-Simulacrum fair points. I think the area that needs to be tested is pretty large, and both my and the test added by this PR are only scratching on the surface. I tried to architect my test in a way that you specify the construct in one place, and the list of things that get passed to the construct in another, and then the test explores the entire matrix built by the combination of both. Then there is no manual step in having to expand the entire matrix manually, and one can test for many scenarios. In the instance of this PR for example, it's not trivially observable that each construct tested has both the match and mismatch case covered. But the approach of this PR also has advantages because it can also test the "binding created" case. Again, it's a gigantic design space. You are right by saying that changes in the stdout file are easy to be missed. They are also easy to be included, as one can pass the |
I think it's worth thinking about how we can expand the testing here to be more complete, for sure. I agree that the coverage added by our tests so far and (in either PR) is likely fairly minimal compared to what we should have -- I wonder if one possibility is some kind of fuzzing here (or other generated test cases), with the intent being to strictly keep current behavior (or at least intentionally change it). Seems tough to make sure we're being exhaustive though; maybe one avenue is to look at --emit=mir or similar and try to make sure that the dropping thing has ended up in every user-code place somehow? |
…r=eholk Drop temporaries created in a condition, even if it's a let chain Fixes rust-lang#100513. During the lowering from AST to HIR we wrap expressions acting as conditions in a `DropTemps` expression so that any temporaries created in the condition are dropped after the condition is executed. Effectively this means we transform ```rust if Some(1).is_some() { .. } ``` into (roughly) ```rust if { let _t = Some(1).is_some(); _t } { .. } ``` so that if we create any temporaries, they're lifted into the new scope surrounding the condition, so for example something along the lines of ```rust if { let temp = Some(1); let _t = temp.is_some(); _t }. ``` Before this PR, if the condition contained any let expressions we would not introduce that new scope, instead leaving the condition alone. This meant that in a let-chain like ```rust if get_drop("first").is_some() && let None = get_drop("last") { println!("second"); } else { .. } ``` the temporary created for `get_drop("first")` would be lifted into the _surrounding block_, which caused it to be dropped after the execution of the entire `if` expression. After this PR, we wrap everything but the `let` expression in terminating scopes. The upside to this solution is that it's minimally invasive, but the downside is that in the worst case, an expression with `let` exprs interspersed like ```rust if get_drop("first").is_some() && let Some(_a) = get_drop("fifth") && get_drop("second").is_some() && let Some(_b) = get_drop("fourth") { .. } ``` gets _multiple_ new scopes, roughly ```rust if { let _t = get_drop("first").is_some(); _t } && let Some(_a) = get_drop("fifth") && { let _t = get_drop("second").is_some(); _t } && let Some(_b) = get_drop("fourth") { .. } ``` so instead of all of the temporaries being dropped at the end of the entire condition, they will be dropped right after they're evaluated (before the subsequent `let` expr). So while I'd say the drop behavior around let-chains is _less_ surprising after this PR, it still might not exactly match what people might expect. For tests, I've just extended the drop order tests added in rust-lang#100526. I'm not sure if that's the best way to go about it, though, so suggestions are welcome.
In #100513 it was shown that the drop behaviour of let_chains is not correct currently. Since drop behaviour is something pretty subtle, this adds explicit tests for the drop behavior of
if
,if let
andmatch
to make sure that it does not regress in the future.The
println!
s were left in to make debugging easier in case something goes wrong, but they are not required for the test.