`Box` deallocates too early with `unsized_fn_params`
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
I tried this code:
#![feature(unsized_fn_params, allocator_api)]
use std::alloc::{Allocator, AllocError, Layout, Global};
use std::ptr::NonNull;
struct LoudDropAllocator;
unsafe impl Allocator for LoudDropAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
Global.allocate(layout)
}
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
println!("deallocate");
unsafe { Global.deallocate(ptr, layout); }
}
}
impl Drop for LoudDropAllocator {
fn drop(&mut self) {
println!("dropping allocator");
}
}
struct Thing(i32);
impl Drop for Thing {
fn drop(&mut self) {
println!("dropping Thing");
}
}
fn main() {
println!("with_sized:");
with_sized(Box::new_in(Thing(1), LoudDropAllocator));
println!();
println!("with_unsized:");
with_unsized(Box::new_in(Thing(1), LoudDropAllocator));
}
fn with_sized<T: Sized>(x: Box<T, LoudDropAllocator>) {
foo(*x);
println!("finished calling foo");
}
fn with_unsized<T: ?Sized>(x: Box<T, LoudDropAllocator>) {
foo(*x);
println!("finished calling foo");
}
fn foo<T: ?Sized>(a: T) {
println!("inside foo");
}
Running the above code results in the following output:
with_sized:
inside foo
dropping Thing
finished calling foo
deallocate
dropping allocator
with_unsized:
inside foo
dropping Thing
deallocate
dropping allocator
finished calling foo
I expected with_sized and with_unsized to have the same behavior. However, they behave differently. That is, when moving a Sized type out of a Box, the Box is dropped later when the variable goes out of scope. But when moving a potentially unsized type out of a Box, the Box is dropped immediately.
I'm guessing that this behavior is probably also observable without the allocator_api feature, but I have not verified this.
cc @beepster4096
Meta
Reproducible on the playground with version 1.93.0-nightly (2025-11-17 0df64c57843a9612c68d)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the provided playground reproduction with nightly Rust 1.93.0 and compare the with_sized and with_unsized paths, including allocator and Thing drop output. Trace the compiler behavior for moving a potentially unsized value out of Box and determine what change makes both paths preserve the expected drop ordering.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100