Skip to content

[Crater experiment] Adjust PlaceMention borrow checking for MIR move elimination semantics - #165046

Draft
Jules-Bertholet wants to merge 4 commits into
rust-lang:mainfrom
Jules-Bertholet:placemention-mir-move-elim
Draft

Jules-Bertholet wants to merge 4 commits into
rust-lang:mainfrom
Jules-Bertholet:placemention-mir-move-elim

Conversation

@Jules-Bertholet

@Jules-Bertholet Jules-Bertholet commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

View all comments

#164812 (comment)

I didn't bother adjusting all the UI tests, so they will fail.

@Amanieu can you confirm that tests/ui/borrowck/placemention-mir-move-elim.rs corresponds to the behavior you want?

@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 Oct 27, 2026
@theemathas

Copy link
Copy Markdown
Contributor

@bors try

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Oct 27, 2026
…=<try>

[Crater experiment] Adjust `PlaceMention` borrow checking for MIR move elimination semantics
@rust-log-analyzer

Copy link
Copy Markdown
Collaborator

The job test-aarch64-gnu-llvm-22-1 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
---- [ui] tests/ui/binding/issue-53114-borrow-checks.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/binding/issue-53114-borrow-checks.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/binding/issue-53114-borrow-checks" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015"
stdout: none
--- stderr -------------------------------
error[E0382]: use of moved value: `m`
##[error]  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:12:13
   |
LL |     let m = M;
   |         - move occurs because `m` has type `M`, which does not implement the `Copy` trait
LL |     drop(m);
   |          - value moved here
LL |     let _ = m; // accepted, and want it to continue to be
   |             ^ value used here after move
   |
note: if `M` implemented `Clone`, you could clone the value
  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:7:1
   |
LL | struct M;
   | ^^^^^^^^ consider implementing `Clone` for this type
...
LL |     drop(m);
   |          - you could clone this value

error[E0382]: use of moved value: `m`
##[error]  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:23:11
   |
LL |     let m = M;
   |         - move occurs because `m` has type `M`, which does not implement the `Copy` trait
LL |     drop(m);
   |          - value moved here
LL |     match m { _ => { } } // #53114: accepted too
   |           ^ value used here after move
   |
note: if `M` implemented `Clone`, you could clone the value
  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:7:1
   |
LL | struct M;
   | ^^^^^^^^ consider implementing `Clone` for this type
...
LL |     drop(m);
   |          - you could clone this value

error[E0382]: use of moved value: `m`
##[error]  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:34:16
   |
LL |     let m = M;
   |         - move occurs because `m` has type `M`, which does not implement the `Copy` trait
LL |     drop(m);
   |          - value moved here
LL |     if let _ = m { } // #53114: accepted too
   |                ^ value used here after move
   |
note: if `M` implemented `Clone`, you could clone the value
  --> /checkout/tests/ui/binding/issue-53114-borrow-checks.rs:7:1
   |
LL | struct M;
   | ^^^^^^^^ consider implementing `Clone` for this type
...
---
---- [ui] tests/ui/reachable/type_ascribe_never_field.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/reachable/type_ascribe_never_field.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/reachable/type_ascribe_never_field" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015"
stdout: none
--- stderr -------------------------------
error[E0381]: used binding `x` isn't initialized
##[error]  --> /checkout/tests/ui/reachable/type_ascribe_never_field.rs:13:12
   |
LL |    let x: (!,);
   |        - binding declared here but left uninitialized
LL |    let _ = type_ascribe!(x.0, _);
   |            ^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0381`.
------------------------------------------

---- [ui] tests/ui/reachable/type_ascribe_never_field.rs stdout end ----
---- [ui] tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs#current stdout ----

error in revision `current`: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--cfg" "current" "--check-cfg" "cfg(test,FALSE,current,next)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.current" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015"
stdout: none
--- stderr -------------------------------
error[E0382]: use of moved value: `obj`
##[error]  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:31:40
   |
LL |     let (obj, t) = foo();
   |          --- move occurs because `obj` has type `Inv<dyn Object<&(), &()>>`, which does not implement the `Copy` trait
LL |     impls_trait(obj, t);
   |                 --- value moved here
LL |     let _: Inv<dyn Object<&(), &()>> = obj;
   |                                        ^^^ value used here after move
   |
note: consider changing this parameter type in function `impls_trait` to borrow instead if owning the value isn't necessary
  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:26:35
   |
LL | fn impls_trait<T: Trait<U>, U>(_: Inv<T>, _: Inv<U>) {}
   |    ----------- in this function   ^^^^^^ this parameter takes ownership of the value
note: if all bounds were met, you could clone the value
  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:22:1
   |
LL | #[derive(Clone, Copy)]
   |          ----- derived `Clone` adds implicit bounds on type parameters
LL | struct Inv<T>(*mut T);
   | ^^^^^^^^^^^-^
   |            |
   |            introduces an implicit `T: Clone` bound
...
LL |     impls_trait(obj, t);
   |                 --- you could clone this value
   = help: consider manually implementing `Clone` to avoid undesired bounds

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0382`.
------------------------------------------

---- [ui] tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs#current stdout end ----
---- [ui] tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs#next stdout ----

error in revision `next`: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--cfg" "next" "--check-cfg" "cfg(test,FALSE,current,next)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.next" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015" "-Znext-solver"
stdout: none
--- stderr -------------------------------
error[E0382]: use of moved value: `obj`
##[error]  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:31:40
   |
LL |     let (obj, t) = foo();
   |          --- move occurs because `obj` has type `Inv<dyn Object<&(), &()>>`, which does not implement the `Copy` trait
LL |     impls_trait(obj, t);
   |                 --- value moved here
LL |     let _: Inv<dyn Object<&(), &()>> = obj;
   |                                        ^^^ value used here after move
   |
note: consider changing this parameter type in function `impls_trait` to borrow instead if owning the value isn't necessary
  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:26:35
   |
LL | fn impls_trait<T: Trait<U>, U>(_: Inv<T>, _: Inv<U>) {}
   |    ----------- in this function   ^^^^^^ this parameter takes ownership of the value
note: if all bounds were met, you could clone the value
  --> /checkout/tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs:22:1
   |
LL | #[derive(Clone, Copy)]
   |          ----- derived `Clone` adds implicit bounds on type parameters
LL | struct Inv<T>(*mut T);
   | ^^^^^^^^^^^-^
   |            |
   |            introduces an implicit `T: Clone` bound
...
LL |     impls_trait(obj, t);
   |                 --- you could clone this value
   = help: consider manually implementing `Clone` to avoid undesired bounds

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0382`.
------------------------------------------

---- [ui] tests/ui/traits/next-solver/assembly/ambiguity-due-to-uniquification-3.rs#next stdout end ----
---- [ui] tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs#next stdout ----

error in revision `next`: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--cfg" "next" "--check-cfg" "cfg(test,FALSE,old,next)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.next" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015" "-Znext-solver"
stdout: none
--- stderr -------------------------------
error[E0382]: use of moved value: `x`
##[error]  --> /checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs:50:25
   |
LL |     let x = None.unwrap();
   |         - move occurs because `x` has type `Foo<u32, u32>`, which does not implement the `Copy` trait
LL |     let y = x;
   |             - value moved here
LL |     let _: Foo<_,  _> = x;
   |                         ^ value used here after move
   |
note: if `Foo<u32, u32>` implemented `Clone`, you could clone the value
  --> /checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs:45:1
   |
LL | struct Foo<T: Trait<Assoc = U>, U>(T);
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
LL |     let y = x;
   |             - you could clone this value

---
---- [ui] tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs#old stdout ----

error in revision `old`: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--cfg" "old" "--check-cfg" "cfg(test,FALSE,old,next)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.old" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015"
stdout: none
--- stderr -------------------------------
error[E0382]: use of moved value: `x`
##[error]  --> /checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs:50:25
   |
LL |     let x = None.unwrap();
   |         - move occurs because `x` has type `Foo<u32, u32>`, which does not implement the `Copy` trait
LL |     let y = x;
   |             - value moved here
LL |     let _: Foo<_,  _> = x;
   |                         ^ value used here after move
   |
note: if `Foo<u32, u32>` implemented `Clone`, you could clone the value
  --> /checkout/tests/ui/traits/next-solver/generalize/subtype-obligations-bivariant-args.rs:45:1
   |
LL | struct Foo<T: Trait<Assoc = U>, U>(T);
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider implementing `Clone` for this type
...
LL |     let y = x;
   |             - you could clone this value

---
---- [ui] tests/ui/uninhabited/diverging-guard.rs stdout ----

error: test compilation failed although it shouldn't!
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/uninhabited/diverging-guard.rs" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/aarch64-unknown-linux-gnu/stage2" "--target=aarch64-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/aarch64-unknown-linux-gnu/test/ui/uninhabited/diverging-guard" "-Znext-solver=coherence" "-A" "unused" "-W" "unused_attributes" "-A" "internal_features" "-A" "incomplete_features" "-A" "unused_parens" "-A" "unused_braces" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/aarch64-unknown-linux-gnu/native/rust-test-helpers" "--edition=2015"
stdout: none
--- stderr -------------------------------
error[E0381]: used binding `x` isn't initialized
##[error]  --> /checkout/tests/ui/uninhabited/diverging-guard.rs:7:11
   |
LL |     let x: Void;
   |         - binding declared here but left uninitialized
LL |     match x {
   |           ^ `x` used here but it isn't initialized
   |
help: consider assigning a value
   |
LL |     let x: Void = /* value */;
   |                 +++++++++++++

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0381`.

@rust-bors

rust-bors Bot commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 636e83d (636e83d88d52bef087e37ddcb9b224b2284c758e)
Base parent: 16d1ffa (16d1ffac17ad8b739e32483ac2e65fe7e1804977)

@theemathas

Copy link
Copy Markdown
Contributor

@craterbot check

@craterbot

Copy link
Copy Markdown
Collaborator

👌 Experiment pr-165046 created and queued.
🤖 Automatically detected try build 636e83d
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Oct 27, 2026
@craterbot

Copy link
Copy Markdown
Collaborator

🚧 Experiment pr-165046 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot

Copy link
Copy Markdown
Collaborator

🎉 Experiment pr-165046 is completed!
📊 264 regressed and 2 fixed (1217468 total)
📊 5862 spurious results on the retry-regressed-list.txt, consider a retry1 if this is a significant amount.
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

Footnotes

  1. re-run the experiment with crates=https://crater-reports.s3.amazonaws.com/pr-165046/retry-regressed-list.txt ↩

@craterbot craterbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-crater Status: Waiting on a crater run to be completed. labels Nov 5, 2026
@Amanieu

Amanieu commented Nov 5, 2026

Copy link
Copy Markdown
Member

Based on a quick skim of the crater results I don't think this is going to fly. let _ = foo seems to be widely used to suppress the dead code warning, even when foo is not initialized.

We might have to simply define PlaceMention to be a no-op if the corresponding local isn't initialized.

@RalfJung

RalfJung commented Nov 5, 2026

Copy link
Copy Markdown
Member

I don't see how a semantics like that could be coherent. let _ = ***x switches between place and value expressions multiple times, there's no way to even evaluate most of that expression if x is not initialized. I don't think we should fundamentally alter the structure of place computation itself to account for this.

We could say that PlaceMention is just always a NOP. That's still a bad semantics IMO since let _ = foo now behaves very differently depending on whether foo is a value expression or a place expression. The desugaring from surface Rust into a sane explicit core calculus will be a messy nightmare.

Or... I've seen worse than 270 regressions. They come from fairly few roots. Even most of the "root results" are not root results, they come from a single macro in "blobby".

@Jules-Bertholet

Jules-Bertholet commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Even most of the "root results" are not root results, they come from a single macro in "blobby".

And in the non-root results, there are 115 failures from an obsolete alpha version of zerocopy.

@RalfJung

RalfJung commented Nov 6, 2026

Copy link
Copy Markdown
Member

115 failures from an alpha version of zerocopy.

Cc @joshlf

@joshlf

joshlf commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Feel free to disregard the zerocopy failures. They come from this function which did the following on to guard against an accidental type-alias change:

        let c = candidate.into_exclusive_or_post_monomorphization_error();

        // ...

        // Confirm that `Maybe` is a type alias for `Ptr` with the validity
        // invariant `Initialized`. Our safety proof depends upon this
        // invariant, and it might change at some point. If that happens, we
        // want this function to stop compiling.
        let _: Ptr<'_, UnsafeCell<T>, (_, _, invariant::Initialized)> = candidate;

This wasn't control flow load-bearing; it was just meant as a sort of compile-time type assertion. AFAICT, it was never published outside of alpha releases (it was added in 0.8.0-alpha.6 in google/zerocopy#912 and then removed in 0.8.0-alpha.19 in google/zerocopy#1619).

newpavlov pushed a commit to RustCrypto/utils that referenced this pull request Nov 7, 2026
…cts` (#1588)

The Rust project is considering a change to the language that
would break `let $field: (); let _ = $field;`:
rust-lang/rust#165046
@newpavlov

Copy link
Copy Markdown
Contributor

I released blobby v0.4.1 with the fix.

@tmiasko

tmiasko commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

If it were necessary to keep accepting the same programs (as in #164812), there is also an alternative semantics where PlaceMention takes the role of StorageAlloc (when place has no deref projections).

@RalfJung

RalfJung commented Nov 9, 2026

Copy link
Copy Markdown
Member

We should not have a semantics with ad-hoc special-cases like "do something different if there are no deref projections".

@tmiasko

tmiasko commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

We should not have a semantics with ad-hoc special-cases like "do something different if there are no deref projections".

This behavior would be consistent with MIR move elimination semantics, which indeed does make such a distinction.

@RalfJung

RalfJung commented Nov 9, 2026

Copy link
Copy Markdown
Member

The behavior of MIR move semantics can be described by carrying a "mode" alongside place evaluation, indicating whether locals should be initialized. That's a compositional way to give rise to the desired semantics without ad-hoc syntactic checks.

I don't think the same is possible here. Place evaluation must either return a place or raise UB. We should IMO not alter the return type of place evaluation to deal with this quirk in the borrow checker.

@tmiasko

tmiasko commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

I am perplexed by your comments. In MIR move elimination semantics are two modes of place evaluation. It is entirely trivial observation that one could use the other mode in PlaceMention. I don't understand why that wouldn't be possible.

@RalfJung

RalfJung commented Nov 9, 2026

Copy link
Copy Markdown
Member

Please spell out a compositional model of place evaluation that achieves "PlaceMention takes the role of StorageAlloc (when place has no deref projections)". Maybe I am missing the obvious.

@tmiasko

tmiasko commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

In context of #163340, this would mean PlaceMention using eval_place_for_write as opposed to eval_place.

@Amanieu

Amanieu commented Nov 9, 2026

Copy link
Copy Markdown
Member

Note that this makes RemovePlaceMention as it currently is unsound: you would have to replace these with StorageAlloc instead of removing them.

@Amanieu

Amanieu commented Nov 9, 2026

Copy link
Copy Markdown
Member

What I had in mind instead was to explicitly skip place evaluation if the base local isn't allocated and there's no deref. So evaluation of a PlaceMention becomes:

if !place.has_deref() && local_state(place.local) == LiveUnallocated {
    // nop
} else {
    eval_place(place)
}

It is a hack, but a necessary one to maintain backwards-compatibility. We could maybe phase it out in the long term with a FCW.

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

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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants