Skip to content

Drop temporaries created in a condition, even if it's a let chain#102998

Merged
bors merged 3 commits into
rust-lang:masterfrom
nathanwhit:let-chains-drop-order
Oct 15, 2022
Merged

Drop temporaries created in a condition, even if it's a let chain#102998
bors merged 3 commits into
rust-lang:masterfrom
nathanwhit:let-chains-drop-order

Conversation

@nathanwhit

Copy link
Copy Markdown
Contributor

Fixes #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

if Some(1).is_some() { .. }

into (roughly)

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

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

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

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

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 #100526. I'm not sure if that's the best way to go about it, though, so suggestions are welcome.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

let_chains desugaring is wrong