Skip to content

Avoid loop_match self-assignment in MIR lowering#155186

Merged
rust-bors[bot] merged 3 commits intorust-lang:mainfrom
cijiugechu:fix/loop-match-no-self-assign
May 1, 2026
Merged

Avoid loop_match self-assignment in MIR lowering#155186
rust-bors[bot] merged 3 commits intorust-lang:mainfrom
cijiugechu:fix/loop-match-no-self-assign

Conversation

@cijiugechu
Copy link
Copy Markdown
Member

@cijiugechu cijiugechu commented Apr 12, 2026

Transform

bb2: {
        PlaceMention(_1);
        _1 = copy _1;
        goto -> bb7;
    }

to

bb2: {
        PlaceMention(_1);
        _4 = copy _1;
        _1 = copy _4;
        goto -> bb7;
    }

Closes #143806

Previous MIR
fn helper() -> u8 {
    let mut _0: u8;
    let mut _1: u8;
    let mut _2: !;
    let mut _3: !;
    scope 1 {
        debug state => _1;
    }

    bb0: {
        StorageLive(_1);
        _1 = const 0_u8;
        FakeRead(ForLet(None), _1);
        StorageLive(_2);
        goto -> bb1;
    }

    bb1: {
        falseUnwind -> [real: bb2, unwind: bb11];
    }

    bb2: {
        PlaceMention(_1);
        _1 = copy _1;
        goto -> bb7;
    }

    bb3: {
        FakeRead(ForMatchedPlace(None), _1);
        unreachable;
    }

    bb4: {
        unreachable;
    }

    bb5: {
        goto -> bb6;
    }

    bb6: {
        goto -> bb8;
    }

    bb7: {
        goto -> bb8;
    }

    bb8: {
        goto -> bb1;
    }

    bb9: {
        unreachable;
    }

    bb10: {
        StorageDead(_2);
        StorageDead(_1);
        return;
    }

    bb11 (cleanup): {
        resume;
    }
}
Current MIR
fn helper() -> u8 {
    let mut _0: u8;
    let mut _1: u8;
    let mut _2: !;
    let mut _3: !;
    let mut _4: u8;
    scope 1 {
        debug state => _1;
    }

    bb0: {
        StorageLive(_1);
        _1 = const 0_u8;
        FakeRead(ForLet(None), _1);
        StorageLive(_2);
        goto -> bb1;
    }

    bb1: {
        falseUnwind -> [real: bb2, unwind: bb11];
    }

    bb2: {
        PlaceMention(_1);
        _4 = copy _1;
        _1 = copy _4;
        goto -> bb7;
    }

    bb3: {
        FakeRead(ForMatchedPlace(None), _1);
        unreachable;
    }

    bb4: {
        unreachable;
    }

    bb5: {
        goto -> bb6;
    }

    bb6: {
        goto -> bb8;
    }

    bb7: {
        goto -> bb8;
    }

    bb8: {
        goto -> bb1;
    }

    bb9: {
        unreachable;
    }

    bb10: {
        StorageDead(_2);
        StorageDead(_1);
        return;
    }

    bb11 (cleanup): {
        resume;
    }
}

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 12, 2026

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 12, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 12, 2026

r? @jdonszelmann

rustbot has assigned @jdonszelmann.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler
  • compiler expanded to 69 candidates
  • Random selection from 11 candidates

@folkertdev folkertdev added the F-loop_match when you match up with someone and they really throw you for a loop label Apr 12, 2026
@folkertdev
Copy link
Copy Markdown
Contributor

Just conceptually, would it not be better to remove the assignment completely? Or does that not work?

I've previously tried to change the code so that the assignment does not get introduced, but that did not work out (it would, from memory, require overhauling a whole bunch of code).

@cijiugechu
Copy link
Copy Markdown
Member Author

Just conceptually, would it not be better to remove the assignment completely? Or does that not work?

I've previously tried to change the code so that the assignment does not get introduced, but that did not work out (it would, from memory, require overhauling a whole bunch of code).

I did consider this approach at first, but I was worried that it might have a fairly significant impact on MIR semantics. Once Rvalue::Use(Operand::Copy(_1)) is removed, it could also affect borrowck’s analysis, so in the end I chose the more conservative approach.

@cijiugechu
Copy link
Copy Markdown
Member Author

Additionally, I also considered the performance impact. I compared the LLVM IR generated by the compiler for loop_match before and after the change, and they were the same, so there should not bring performance regression.

@jdonszelmann
Copy link
Copy Markdown
Contributor

r? @folkertdev

@rustbot rustbot assigned folkertdev and unassigned jdonszelmann Apr 16, 2026
@folkertdev
Copy link
Copy Markdown
Contributor

Just conceptually, would it not be better to remove the assignment completely? Or does that not work?
I've previously tried to change the code so that the assignment does not get introduced, but that did not work out (it would, from memory, require overhauling a whole bunch of code).

I did consider this approach at first, but I was worried that it might have a fairly significant impact on MIR semantics. Once Rvalue::Use(Operand::Copy(_1)) is removed, it could also affect borrowck’s analysis, so in the end I chose the more conservative approach.

I'm sceptical of this if the original MIR had a Copy operation, but I'm not really sure.

r? WaffleLapkin do you know, or else who should we ask about this?

At a high level the fix does make sense to me, and the tests look good, so r=me for that.

@rustbot rustbot assigned WaffleLapkin and unassigned folkertdev Apr 20, 2026
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 20, 2026

WaffleLapkin is not on the review rotation at the moment.
They may take a while to respond.

Comment thread tests/mir-opt/building/loop_match_no_self_assign.rs
Comment thread compiler/rustc_mir_build/src/builder/expr/into.rs Outdated
@WaffleLapkin WaffleLapkin added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Apr 24, 2026
@rust-log-analyzer

This comment has been minimized.

@cijiugechu cijiugechu force-pushed the fix/loop-match-no-self-assign branch from e347227 to 52bd93d Compare April 26, 2026 06:39
@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 26, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@cijiugechu cijiugechu added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Apr 26, 2026
Copy link
Copy Markdown
Contributor

@folkertdev folkertdev left a comment

Choose a reason for hiding this comment

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

This seems fine to me, unless Waffle has lingering concerns. The copy should just be cleaned up by later MIR passes, or in any case by LLVM.

Linking for posterity #t-compiler/mir-opts > Semantic of assignment.

View changes since this review

@WaffleLapkin
Copy link
Copy Markdown
Member

@bors r=folkertdev,WaffleLapkin

@rust-bors
Copy link
Copy Markdown
Contributor

rust-bors Bot commented May 1, 2026

📌 Commit 52bd93d has been approved by folkertdev,WaffleLapkin

It is now in the queue for this repository.

@rust-bors rust-bors Bot added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels May 1, 2026
rust-bors Bot pushed a commit that referenced this pull request May 1, 2026
…uwer

Rollup of 9 pull requests

Successful merges:

 - #149637 (Do not run jump-threading for GPUs)
 - #154971 (Verify that penultimate segment of enum variant path refers to enum if it has args)
 - #155186 (Avoid loop_match self-assignment in MIR lowering)
 - #155948 (Fix order-dependent visibility diagnostics)
 - #156001 (ssa-range-prop: fix ICE when encountering self-domiating bb)
 - #155600 (Adds a couple UI tests for polonius)
 - #155995 (-Zembed-source: also embed external source)
 - #156019 (Feed cleanups)
 - #156031 (Return a single diagnostic from `lex_token_trees`.)
@rust-bors rust-bors Bot merged commit 9996d99 into rust-lang:main May 1, 2026
11 checks passed
@rustbot rustbot added this to the 1.97.0 milestone May 1, 2026
rust-timer added a commit that referenced this pull request May 1, 2026
Rollup merge of #155186 - cijiugechu:fix/loop-match-no-self-assign, r=folkertdev,WaffleLapkin

Avoid loop_match self-assignment in MIR lowering

Transform
```
bb2: {
        PlaceMention(_1);
        _1 = copy _1;
        goto -> bb7;
    }
```
to
```
bb2: {
        PlaceMention(_1);
        _4 = copy _1;
        _1 = copy _4;
        goto -> bb7;
    }
```

Closes #143806

<details>
<summary>Previous MIR</summary>

```
fn helper() -> u8 {
    let mut _0: u8;
    let mut _1: u8;
    let mut _2: !;
    let mut _3: !;
    scope 1 {
        debug state => _1;
    }

    bb0: {
        StorageLive(_1);
        _1 = const 0_u8;
        FakeRead(ForLet(None), _1);
        StorageLive(_2);
        goto -> bb1;
    }

    bb1: {
        falseUnwind -> [real: bb2, unwind: bb11];
    }

    bb2: {
        PlaceMention(_1);
        _1 = copy _1;
        goto -> bb7;
    }

    bb3: {
        FakeRead(ForMatchedPlace(None), _1);
        unreachable;
    }

    bb4: {
        unreachable;
    }

    bb5: {
        goto -> bb6;
    }

    bb6: {
        goto -> bb8;
    }

    bb7: {
        goto -> bb8;
    }

    bb8: {
        goto -> bb1;
    }

    bb9: {
        unreachable;
    }

    bb10: {
        StorageDead(_2);
        StorageDead(_1);
        return;
    }

    bb11 (cleanup): {
        resume;
    }
}
```

</details>

<details>
<summary>Current MIR</summary>

```
fn helper() -> u8 {
    let mut _0: u8;
    let mut _1: u8;
    let mut _2: !;
    let mut _3: !;
    let mut _4: u8;
    scope 1 {
        debug state => _1;
    }

    bb0: {
        StorageLive(_1);
        _1 = const 0_u8;
        FakeRead(ForLet(None), _1);
        StorageLive(_2);
        goto -> bb1;
    }

    bb1: {
        falseUnwind -> [real: bb2, unwind: bb11];
    }

    bb2: {
        PlaceMention(_1);
        _4 = copy _1;
        _1 = copy _4;
        goto -> bb7;
    }

    bb3: {
        FakeRead(ForMatchedPlace(None), _1);
        unreachable;
    }

    bb4: {
        unreachable;
    }

    bb5: {
        goto -> bb6;
    }

    bb6: {
        goto -> bb8;
    }

    bb7: {
        goto -> bb8;
    }

    bb8: {
        goto -> bb1;
    }

    bb9: {
        unreachable;
    }

    bb10: {
        StorageDead(_2);
        StorageDead(_1);
        return;
    }

    bb11 (cleanup): {
        resume;
    }
}
```
</details>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

F-loop_match when you match up with someone and they really throw you for a loop 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.

ICE: loop match: broken mir encountered 'Assign' statement with overlapping memory

6 participants