Skip to content

Conversation

dingxiangfei2009
Copy link
Contributor

@dingxiangfei2009 dingxiangfei2009 commented Aug 11, 2025

Fix #143671

It turns out that MIR builder materialise X in [X; 0] into a temporary local when X is unsizing a const. This led to a confusing call to destructor of X when such a destructor is declared. Playground

This patch may miss out other cases that we should avoid materialisation in case of [X; 0]. Suggestions to include is most welcome!

@rustbot
Copy link
Collaborator

rustbot commented Aug 11, 2025

r? @nnethercote

rustbot has assigned @nnethercote.
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

@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 Aug 11, 2025
@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the fold-coercion-into-const branch from 6a64501 to b7b9519 Compare August 11, 2025 22:54
@dingxiangfei2009
Copy link
Contributor Author

A question to @traviscross ...

Should we also need to run this through t-lang as well? It is hard to imagine that anything would rely on destructor called in this way, but I am not sure.

@traviscross traviscross added T-lang Relevant to the language team and removed T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 11, 2025
@traviscross
Copy link
Contributor

A question to @traviscross ...

Should we also need to run this through t-lang as well? It is hard to imagine that anything would rely on destructor called in this way, but I am not sure.

Well, let's see. It looks like this issue does affect the user-visible stable behavior of the language:

use core::{mem, ptr, sync::atomic::{AtomicU64, Ordering}};

static COUNT: AtomicU64 = AtomicU64::new(0);

struct S;
impl Drop for S {
    fn drop(&mut self) {
        COUNT.fetch_add(1, Ordering::Relaxed);
    }
}
trait Tr {}
impl Tr for S {}

const X: Box<dyn Tr> = unsafe {
    mem::transmute::<_, Box<S>>(ptr::dangling_mut::<S>())
};

fn main() {
    assert_eq!(0, COUNT.load(Ordering::Relaxed));
    let _a: &'static [Box<dyn Tr>; 0] = &[X; 0];
    assert_eq!(1, COUNT.load(Ordering::Relaxed));
    //~^ Drop was run.
    let _b = [X; 0];
    assert_eq!(1, COUNT.load(Ordering::Relaxed));
    //~^ Drop wasn't run.
}

So, yes, it's ours to fix via FCP.

Anyone think we need a crater run? For my part, I could go either way on that, and I do want us to fix this, so let's:

@rfcbot fcp merge

@rustbot labels +I-lang-nominated +needs-fcp

cc @rust-lang/lang @rust-lang/lang-advisors

@rfcbot
Copy link

rfcbot commented Aug 11, 2025

Team member @traviscross has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

cc @rust-lang/lang-advisors: FCP proposed for lang, please feel free to register concerns.
See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Aug 11, 2025
@rustbot rustbot added 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. labels Aug 11, 2025
@rfcbot rfcbot added the disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. label Aug 11, 2025
@theemathas
Copy link
Contributor

theemathas commented Aug 12, 2025

Another fun edge case where this change is visible in user code: This code compiles with this PR, but fails on nightly due to dropping in const

use std::rc::Weak;

const X: Weak<i32> = Weak::new();
const Y: [Weak<dyn Send>; 0] = [X; 0];


/// Recursively inspect a THIR expression and probe through unsizing
/// operations that can be const-folded today.
fn check_constness(&self, mut ek: &'a ExprKind<'tcx>) -> bool {
Copy link
Contributor

Choose a reason for hiding this comment

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

s/ek/kind/

I've never seen ek used for an ExprKind, kind is the normal name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! Renamed.

@traviscross traviscross added the P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang label Aug 12, 2025
@nnethercote
Copy link
Contributor

The code changes seem fine, speaking as a reviewer who is not at all familiar with the MIR building and relevant lang details. The example from @theemathas might be worth adding to the test case.

@dingxiangfei2009
Copy link
Contributor Author

@bors try

@rust-bors

This comment has been minimized.

rust-bors bot added a commit that referenced this pull request Aug 12, 2025
…<try>

Do not materialise X in [X; 0] when X is unsizing a const
@dingxiangfei2009
Copy link
Contributor Author

Okay, I will request a crater run ahead of the next meeting.

@dingxiangfei2009
Copy link
Contributor Author

I will push a commit to include the second test cases.

@rust-bors
Copy link

rust-bors bot commented Aug 12, 2025

☀️ Try build successful (CI)
Build commit: 981ca44 (981ca440e18f6cc4bc9026d4be8ddb1ca8378af7, parent: a1531335fe2807715fff569904d99602022643a7)

@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Aug 12, 2025

Hello team. I would like to request

@ craterbot run mode=build-and-test crates=top-100

for a quick triage. 🙇

@nnethercote
Copy link
Contributor

Let's do the top 1000, just for more coverage :)

@craterbot run mode=build-and-test crates=top-1000

@craterbot
Copy link
Collaborator

👌 Experiment pr-145277 created and queued.
🤖 Automatically detected try build 981ca44
⚠️ Try build based on commit c1ab3ed, but latest commit is 8444dde. Did you forget to make a new try build?
🔍 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

@theemathas
Copy link
Contributor

We're basically engaging in a game of whack-a-mole with the MIR builder about the exact shapes that the MIR for [X; 0] can have.

I found some similar-ish behavior with transmute instead of arrays. #146917

@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Sep 23, 2025

@theemathas @traviscross @RalfJung

It seems that an explicit cast in the language _ as _ has significance, in the sense that it gets compiled into a value expression. Therefore, X as WithCoerce<dyn Trait> get compiled into THIR Use expression.

That has the following definition.

/// Forces its contents to be treated as a value expression, not a place
/// expression. This is inserted in some places where an operation would
/// otherwise be erased completely (e.g. some no-op casts), but we still
/// need to ensure that its operand is treated as a value and not a place.
Use {
source: ExprId,
},

How shall we interpret this? I read this as "disregard whether this could be a constant, build it as a value anyway."

Specifically for our example, it is lowered into

Scope {
    PointerCoercion {
        ValueTypeAscription {
            Use {
                NamedConst(X) } } } }

The consequence is that a drop will happen.

@RalfJung
Copy link
Member

Constants are values, so I can't make sense of "treat as value not constant".

dingxiangfei2009 and others added 3 commits September 25, 2025 01:54
Signed-off-by: Ding Xiang Fei <dingxiangfei2009@protonmail.ch>
Co-authored-by: Theemathas Chirananthavat <theemathas@gmail.com>
@rustbot
Copy link
Collaborator

rustbot commented Sep 24, 2025

This PR was rebased onto a different master 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.

@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Sep 24, 2025

I will open an issue for discussion on a future fix plan. The categorisation of the repeated operand could use some better, thorough analysis from the compiler, so that we can have a consistent evaluation strategy.

@dingxiangfei2009
Copy link
Contributor Author

@rustbot ready

I have added a test and additional predicates on the repeated expression.

@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 24, 2025
@traviscross
Copy link
Contributor

traviscross commented Sep 24, 2025

We talked about this in the lang/RfL call with most of us who had checked a box present and agreed that this caveat about as casts doesn't disturb our FCP as long as landing this doesn't make it harder to fix that case as well.

@nnethercote
Copy link
Contributor

I will open an issue for discussion on a future fix plan. The categorisation of the repeated operand could use some better, thorough analysis from the compiler, so that we can have a consistent evaluation strategy.

Once you have made the PR, please link to it from here. Otherwise, I think this has been discussed sufficiently.

@bors r+

@bors
Copy link
Collaborator

bors commented Sep 24, 2025

📌 Commit b77de83 has been approved by nnethercote

It is now in the queue for this repository.

@bors bors 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 Sep 24, 2025
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Sep 25, 2025
…o-const, r=nnethercote

Do not materialise X in [X; 0] when X is unsizing a const

Fix rust-lang#143671

It turns out that MIR builder materialise `X` in `[X; 0]` into a temporary local when `X` is unsizing a `const`. This led to a confusing call to destructor of `X` when such a destructor is declared. [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=8dfc933af89efeb89c881bc77498ba63)

This patch may miss out other cases that we should avoid materialisation in case of `[X; 0]`. Suggestions to include is most welcome!
@dingxiangfei2009
Copy link
Contributor Author

Let's move discussion on a proper and comprehensive fix to the next issue #147021

bors added a commit that referenced this pull request Sep 25, 2025
Rollup of 14 pull requests

Successful merges:

 - #145067 (RawVecInner: add missing `unsafe` to unsafe fns)
 - #145277 (Do not materialise X in [X; 0] when X is unsizing a const)
 - #145973 (Add `std` support for `armv7a-vex-v5`)
 - #146667 (Add an attribute to check the number of lanes in a SIMD vector after monomorphization)
 - #146735 (unstably constify float mul_add methods)
 - #146737 (f16_f128: enable some more tests in Miri)
 - #146766 (Add attributes for #[global_allocator] functions)
 - #146905 (llvm: update remarks support on LLVM 22)
 - #146982 (Remove erroneous normalization step in `tests/run-make/linker-warning`)
 - #147005 (Small string formatting cleanup)
 - #147007 (Explicitly note `&[SocketAddr]` impl of `ToSocketAddrs`)
 - #147008 (bootstrap.py: Respect build.jobs while building bootstrap tool)
 - #147013 (rustdoc: Fix documentation for `--doctest-build-arg`)
 - #147015 (Use `LLVMDisposeTargetMachine`)

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit 21b0e12 into rust-lang:master Sep 25, 2025
10 checks passed
@rustbot rustbot added this to the 1.92.0 milestone Sep 25, 2025
rust-timer added a commit that referenced this pull request Sep 25, 2025
Rollup merge of #145277 - dingxiangfei2009:fold-coercion-into-const, r=nnethercote

Do not materialise X in [X; 0] when X is unsizing a const

Fix #143671

It turns out that MIR builder materialise `X` in `[X; 0]` into a temporary local when `X` is unsizing a `const`. This led to a confusing call to destructor of `X` when such a destructor is declared. [Playground](https://play.rust-lang.org/?version=nightly&mode=debug&edition=2024&gist=8dfc933af89efeb89c881bc77498ba63)

This patch may miss out other cases that we should avoid materialisation in case of `[X; 0]`. Suggestions to include is most welcome!
github-actions bot pushed a commit to rust-lang/miri that referenced this pull request Sep 26, 2025
Rollup of 14 pull requests

Successful merges:

 - rust-lang/rust#145067 (RawVecInner: add missing `unsafe` to unsafe fns)
 - rust-lang/rust#145277 (Do not materialise X in [X; 0] when X is unsizing a const)
 - rust-lang/rust#145973 (Add `std` support for `armv7a-vex-v5`)
 - rust-lang/rust#146667 (Add an attribute to check the number of lanes in a SIMD vector after monomorphization)
 - rust-lang/rust#146735 (unstably constify float mul_add methods)
 - rust-lang/rust#146737 (f16_f128: enable some more tests in Miri)
 - rust-lang/rust#146766 (Add attributes for #[global_allocator] functions)
 - rust-lang/rust#146905 (llvm: update remarks support on LLVM 22)
 - rust-lang/rust#146982 (Remove erroneous normalization step in `tests/run-make/linker-warning`)
 - rust-lang/rust#147005 (Small string formatting cleanup)
 - rust-lang/rust#147007 (Explicitly note `&[SocketAddr]` impl of `ToSocketAddrs`)
 - rust-lang/rust#147008 (bootstrap.py: Respect build.jobs while building bootstrap tool)
 - rust-lang/rust#147013 (rustdoc: Fix documentation for `--doctest-build-arg`)
 - rust-lang/rust#147015 (Use `LLVMDisposeTargetMachine`)

r? `@ghost`
`@rustbot` modify labels: rollup
@dingxiangfei2009 dingxiangfei2009 deleted the fold-coercion-into-const branch September 26, 2025 19:06
github-actions bot pushed a commit to model-checking/verify-rust-std that referenced this pull request Oct 9, 2025
Rollup of 14 pull requests

Successful merges:

 - rust-lang#145067 (RawVecInner: add missing `unsafe` to unsafe fns)
 - rust-lang#145277 (Do not materialise X in [X; 0] when X is unsizing a const)
 - rust-lang#145973 (Add `std` support for `armv7a-vex-v5`)
 - rust-lang#146667 (Add an attribute to check the number of lanes in a SIMD vector after monomorphization)
 - rust-lang#146735 (unstably constify float mul_add methods)
 - rust-lang#146737 (f16_f128: enable some more tests in Miri)
 - rust-lang#146766 (Add attributes for #[global_allocator] functions)
 - rust-lang#146905 (llvm: update remarks support on LLVM 22)
 - rust-lang#146982 (Remove erroneous normalization step in `tests/run-make/linker-warning`)
 - rust-lang#147005 (Small string formatting cleanup)
 - rust-lang#147007 (Explicitly note `&[SocketAddr]` impl of `ToSocketAddrs`)
 - rust-lang#147008 (bootstrap.py: Respect build.jobs while building bootstrap tool)
 - rust-lang#147013 (rustdoc: Fix documentation for `--doctest-build-arg`)
 - rust-lang#147015 (Use `LLVMDisposeTargetMachine`)

r? `@ghost`
`@rustbot` modify labels: rollup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. needs-fcp This change is insta-stable, or significant enough to need a team FCP to proceed. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-lang Relevant to the language team to-announce Announce this issue on triage meeting

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unsize-coercible type causes [SOME_CONST; 0] to execute Drop, but only if type is annotated.