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

Improve behavior of IF_LET_RESCOPE around temporaries and place expressions #137444

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

compiler-errors
Copy link
Member

@compiler-errors compiler-errors commented Feb 22, 2025

Heavily reworks the IF_LET_RESCOPE to be more sensitive around 1. temporaries that get consumed/terminated and therefore should not trigger the lint, and 2. borrows of place expressions, which are not temporary values.

Fixes #137411

@compiler-errors
Copy link
Member Author

cc @dingxiangfei2009 #107251 (and @jieyouxu who reviewed it)

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Feb 22, 2025
Copy link
Contributor

@traviscross traviscross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@steffahn
Copy link
Member

steffahn commented Feb 23, 2025

The #137376 fix would need to be a bit restricted to limit false negatives.

If the if let … is not sufficiently non-nested, we need to consider that semantics where changed in two ways: the temporaries (in edition 2021) lived throughout the else, but also the whole if let … didn’t bound the temporaries, either!

E.g. wrapping a if let … else into another function calls:

#![warn(rust_2024_compatibility)]

struct Droppy(u16);
impl Drop for Droppy {
    fn drop(&mut self) {
        println!("drop(Droppy({}))", self.0)
    }
}

fn do_stuff_with(property: bool) {
    println!("do_stuff_with({property})");
}

fn main() {
    f1();
    f2();
}

fn f1() {
    println!("==================== f1 ====================");
    do_stuff_with(if let Some(_x) = Some(Droppy(1337)) {
        true
    } else {
        false
    });
}

fn f2() {
    println!("==================== f2 ====================");
    do_stuff_with(if let Some(_x) = Some((Droppy(42), Droppy(69)).0) {
        true
    } else {
        false
    });
}

2021:

 ==================== f1 ====================
 drop(Droppy(1337))
 do_stuff_with(true)
 ==================== f2 ====================
 drop(Droppy(42))
 do_stuff_with(true)
 drop(Droppy(69))

2024:

 ==================== f1 ====================
 drop(Droppy(1337))
 do_stuff_with(true)
 ==================== f2 ====================
 drop(Droppy(42))
 drop(Droppy(69))
 do_stuff_with(true)

At least in the second case, there’s still a temporary left that escapes the if let.

And if the pattern does not consume the contents of the Some the effects are even more significant, e.g. replacing Some(x_) with Some(_):
2021:

 ==================== f1 ====================
 do_stuff_with(true)
 drop(Droppy(1337))
 ==================== f2 ====================
 do_stuff_with(true)
 drop(Droppy(42))
 drop(Droppy(69))

2024:

 ==================== f1 ====================
 drop(Droppy(1337))
 do_stuff_with(true)
 ==================== f2 ====================
 drop(Droppy(42))
 drop(Droppy(69))
 do_stuff_with(true)

so well… one could either conservatively trying to just keep the lint on all of these [of course currently, they are all linted], or trying to notice the specific un-problematic case.

Half of noticing the specific case was about whether there are any other temporaries around. Those are arguably still relevant even without any do_stuff_with wrapping, though! So I suppose these need handling, anyway…

fn f3() {
    if let Some(()) = (Droppy(123), None).1 {} else {
        println!("else {{\n\n}}");
    };
}

2021:

 else {
     …
 }
 drop(Droppy(123))

2024:

 drop(Droppy(123))
 else {
     …
 }

also compare the playground linked in #133753

@compiler-errors
Copy link
Member Author

Ok, well I don't think #137376 is fixable in general given how little information we have in this point of the compiler about match exhaustivity and what temporaries have definitely been "accounted for" (i.e. moved or dropped).

The case of (...).field affects #137411 too, so I'll fix that, but I'll probably back out the last commit. Too bad!

@traviscross
Copy link
Contributor

Perhaps you were already doing this, but it seems worthwhile to capture @steffahn's examples there as tests so that if someone tries again, we'll have to confront those.

@compiler-errors
Copy link
Member Author

@steffahn is welcome to put up a separate PR to make them into tests.

@oli-obk
Copy link
Contributor

oli-obk commented Feb 25, 2025

@bors r+ rollup

@bors
Copy link
Contributor

bors commented Feb 25, 2025

📌 Commit bad8e98 has been approved by oli-obk

It is now in the queue for this repository.

@bors bors added the S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. label Feb 25, 2025
@oli-obk oli-obk added beta-nominated Nominated for backporting to the compiler in the beta channel. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Feb 25, 2025
@oli-obk oli-obk assigned oli-obk and unassigned cjgillot Feb 25, 2025
fmease added a commit to fmease/rust that referenced this pull request Feb 25, 2025
Improve behavior of `IF_LET_RESCOPE` around temporaries and place expressions

Heavily reworks the `IF_LET_RESCOPE` to be more sensitive around 1. temporaries that get consumed/terminated and therefore should not trigger the lint, and 2. borrows of place expressions, which are not temporary values.

Fixes rust-lang#137411
bors added a commit to rust-lang-ci/rust that referenced this pull request Feb 25, 2025
Rollup of 8 pull requests

Successful merges:

 - rust-lang#137370 (adjust_abi: make fallback logic for ABIs a bit easier to read)
 - rust-lang#137444 (Improve behavior of `IF_LET_RESCOPE` around temporaries and place expressions)
 - rust-lang#137464 (Fix invalid suggestion from type error for derive macro)
 - rust-lang#137539 ( Add rustdoc-gui regression test for rust-lang#137082 )
 - rust-lang#137576 (Don't doc-comment BTreeMap<K, SetValZST, A>)
 - rust-lang#137595 (remove `simd_fpow` and `simd_fpowi`)
 - rust-lang#137600 (type_ir: remove redundant part of comment)
 - rust-lang#137602 (feature: fix typo in attribute description)

r? `@ghost`
`@rustbot` modify labels: rollup
@traviscross traviscross added I-edition-triaged Issue: This issue has been reviewed and triaged by the Edition team. and removed I-edition-triaged Issue: This issue has been reviewed and triaged by the Edition team. labels Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
beta-nominated Nominated for backporting to the compiler in the beta channel. 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.

False postive for if-let-rescope on hashbrown::HashMap::get?
7 participants