Skip to content

Reborrow &mut on every move - #163494

Open
Jules-Bertholet wants to merge 20 commits into
rust-lang:mainfrom
Jules-Bertholet:universal-mut-reborrow
Open

Jules-Bertholet wants to merge 20 commits into
rust-lang:mainfrom
Jules-Bertholet:universal-mut-reborrow

Conversation

@Jules-Bertholet

@Jules-Bertholet Jules-Bertholet commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

View all comments


From the Reference:

Moved and copied types

When a place expression is evaluated in a value expression context, or is bound by value in a pattern, it denotes the value held in that memory location.

If the type of that value implements Copy, then the value will be copied.

In the remaining situations, if that type is Sized, then it may be possible to move the value.

[…]

This PR adds one exception to the above rules: if the type of the value is an &mut _ mutable reference, the value will now always be reborrowed instead of moved.

This allows the following to compile:

fn generic(_: impl Sized) {}
fn assert_fnmut(_: &mut impl FnMut()) {}

struct Foo<T>(T);

fn main() {
    let mut_ref = &mut ();
    generic(mut_ref);
    {
        mut_ref
    };
    let _local = mut_ref;
    let _ = || mut_ref;
    let mut _tup: (&mut (),) = (&mut (),);
    _tup.0 = mut_ref;
    Foo(mut_ref);
    Foo { 0: mut_ref };
    let mut f = || {
        let _y: &mut _ = mut_ref;
    };
    f();
    f();
    assert_fnmut(&mut f);
    generic(mut_ref);

    let mut_ref_ref = &mut &mut ();
    generic(*mut_ref_ref);
    let _local = *mut_ref_ref;
    let _ = || *mut_ref_ref;
    let mut _tup: (&mut (),) = (&mut (),);
    _tup.0 = *mut_ref_ref;
    Foo(*mut_ref_ref);
    Foo { 0: *mut_ref_ref };
    let mut f = || {
        let _y: &mut _ = *mut_ref_ref;
    };
    f();
    f();
    assert_fnmut(&mut f);
    generic(*mut_ref_ref);
}

Unfortunately, the following continues to not compile:

fn assert_fnmut(_: &mut impl FnMut()) {}
fn main() {
    let x = &mut ();
    let mut f = || {
        //~^ ERROR expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` [E0525]
        let _y = x;
    };
    f();
    f();
    assert_fnmut(f);
}

This last case is unfortunately very difficult to fix at present. See #47478 for discussion.

When #![feature(reborrow)] (#145612) is enabled, we also insert reborrows for concrete types implementing Reborrow.

@rustbot label A-MIR A-borrow-checker T-lang needs-fcp

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Sep 29, 2026
Comment thread compiler/rustc_mir_build/src/builder/misc.rs Outdated

@lcnr lcnr left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

should then probably also remove the explicit reborrows in HIR typeck?

View changes since this review

@dianne

dianne commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

should then probably also remove the explicit reborrows in HIR typeck?

would that work without changing closure upvar inference to match? e.g. I think this closure captures x by mut ref (and accordingly is a FnMut) only because _y's declaration has a type annotation on it that causes coercing to insert a reborrow:

fn main() {
    let x = &mut ();
    let mut f = || {
        let _y: &mut _ = x;
    };
    f();
    f();
}

without the annotation, it captures x by value and fails to compile

edit: oh, of course, this makes the MIR for constructing the closure do the reborrow since it uses consume_by_copy_reborrow_or_move

edit 2: but it'd still be inferred to be a FnOnce, wouldn't it, if it has by-value captures?

@rust-log-analyzer

This comment has been minimized.

@Jules-Bertholet
Jules-Bertholet marked this pull request as ready for review September 29, 2026 18:06
@rustbot

rustbot commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in match lowering

cc @Nadrieril

@rustbot rustbot 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 Sep 29, 2026
@rustbot

rustbot commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

r? @adwinwhite

rustbot has assigned @adwinwhite.
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 77 candidates
  • Random selection from 19 candidates

@rustbot rustbot added A-borrow-checker Area: The borrow checker A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. T-lang Relevant to the language team labels Sep 29, 2026
@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

#163494 (comment): I don't understand MIR optimizations, don't feel confident touching these tests. Someone who knows more than I do will need to take a look

@rust-log-analyzer

This comment has been minimized.

@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

@rustbot label F-reborrow

@rustbot rustbot added the F-reborrow `#![feature(reborrow)]`; see #145612 label Sep 29, 2026
@rustbot

rustbot commented Sep 29, 2026

Copy link
Copy Markdown
Collaborator

This PR changes a file inside tests/crashes. If a crash was fixed, please move into the corresponding ui subdir and add 'Fixes #' to the PR description to autoclose the issue upon merge.

@rust-log-analyzer

This comment has been minimized.

@rustbot

rustbot commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in rustc_ty_utils::consts.rs

cc @BoxyUwU

Some changes occurred in match checking

cc @Nadrieril

@rust-log-analyzer

This comment has been minimized.

Comment thread compiler/rustc_mir_build/src/thir/print.rs Outdated
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

I am trying to fix the remaining mir-opt regression, but it's a little tough. If I improve CopyProp so that it recognizes &mut → &mut reborrows as a form of copy, that in turn pessimizes ReferencePropagation because it will consider fewer locals fully replaceable.

@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

Hmm, so it looks like all the optimizations that are lost in CopyProp get recovered in ReferencePropagation. So there is only an actual optimization regression in opt-level=0 builds (where ReferencePropagation is not enabled). So maybe this is fine?

@rust-log-analyzer

This comment has been minimized.

We don't need these anymore,
now that the reborrows get inserted in MIR.

We still need some trace in HIR for closure capture inference,
so use `FakeMutReborrow` for that.
This appears to be a strict optimization.
@rustbot

rustbot commented Oct 1, 2026

Copy link
Copy Markdown
Collaborator

This PR changes MIR

cc @oli-obk, @RalfJung, @JakobDegen, @vakaras

@nnethercote

Copy link
Copy Markdown
Contributor

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Oct 2, 2026
@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Oct 2, 2026
@rust-bors

rust-bors Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: c842e75 (c842e7577a58e3d96e5e86c7b7f0649bb84ae4f8)
Base parent: c36f145 (c36f1457196e315bc204b9564a6a5a7fe7f5a51f)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (c842e75): comparison URL.

Overall result: ✅ improvements - no action needed

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf -perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.6% [-0.9%, -0.1%] 9
Improvements ✅
(secondary)
-0.2% [-0.2%, -0.2%] 1
All ❌✅ (primary) -0.6% [-0.9%, -0.1%] 9

Max RSS (memory usage)

Results (primary 1.1%, secondary -1.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
3.8% [2.9%, 4.7%] 2
Regressions ❌
(secondary)
4.3% [4.3%, 4.3%] 1
Improvements ✅
(primary)
-4.3% [-4.3%, -4.3%] 1
Improvements ✅
(secondary)
-2.9% [-4.2%, -0.7%] 3
All ❌✅ (primary) 1.1% [-4.3%, 4.7%] 3

Cycles

Results (secondary 4.1%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
4.1% [2.9%, 6.2%] 3
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) - - 0

Binary size

Results (primary 0.0%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.1% [0.1%, 0.5%] 7
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-0.1% [-0.2%, -0.1%] 4
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 0.0% [-0.2%, 0.5%] 11

Bootstrap: 489.203s -> 490.429s (0.25%)
Artifact size: 406.46 MiB -> 406.52 MiB (0.02%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Oct 2, 2026
@Jules-Bertholet

Copy link
Copy Markdown
Contributor Author

@rustbot label I-lang-nominated

@rustbot rustbot added the I-lang-nominated Nominated for discussion during a lang team meeting. label Oct 2, 2026
/// CoerceShared. These may be end up implemented as multiple MIR operations.
///
/// This is produced by the [`ExprKind::Reborrow`].
/// This is produced by the [`ExprKind::CoerceShared`],

@RalfJung RalfJung Oct 2, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
/// This is produced by the [`ExprKind::CoerceShared`],
/// This is produced by [`ExprKind::CoerceShared`],

(I know this is pre-existing, but you're touching this comment anyway)

View changes since the review

This branch has not been deployed

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

Labels

A-borrow-checker Area: The borrow checker A-MIR Area: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.html F-reborrow `#![feature(reborrow)]`; see #145612 I-lang-nominated Nominated for discussion during a lang team meeting. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. 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. T-lang Relevant to the language team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants