Skip to content

Commit

Permalink
allocate before calling T::default in <Box<T>>::default()
Browse files Browse the repository at this point in the history
The `Box<T: Default>` impl currently calls `T::default()` before allocating
the `Box`.

Most `Default` impls are trivial, which should in theory allow
LLVM to construct `T: Default` directly in the `Box` allocation when calling
`<Box<T>>::default()`.

However, the allocation may fail, which necessitates calling `T's` destructor if it has one.
If the destructor is non-trivial, then LLVM has a hard time proving that it's
sound to elide, which makes it construct `T` on the stack first, and then copy it into the allocation.

Create an uninit `Box` first, and then write `T::default` into it, so that LLVM now only needs to prove
that the `T::default` can't panic, which should be trivial for most `Default` impls.
  • Loading branch information
jwong101 committed Oct 10, 2024
1 parent 8a14622 commit dd0620b
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 3 deletions.
2 changes: 1 addition & 1 deletion library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1688,7 +1688,7 @@ impl<T: Default> Default for Box<T> {
/// Creates a `Box<T>`, with the `Default` value for T.
#[inline]
fn default() -> Self {
Box::new(T::default())
Box::write(Box::new_uninit(), T::default())
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/codegen/placement-new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use std::sync::Arc;
// CHECK-LABEL: @box_default_inplace
#[no_mangle]
pub fn box_default_inplace() -> Box<(String, String)> {
// CHECK: [[ALLOCA:%.*]] = alloca
// CHECK-NOT: alloca
// CHECK: [[BOX:%.*]] = {{.*}}call {{.*}}__rust_alloc(
// CHECK: call void @llvm.memcpy{{.*}}(ptr {{.*}}[[BOX]], ptr {{.*}}[[ALLOCA]]
// CHECK-NOT: call void @llvm.memcpy
// CHECK: ret ptr [[BOX]]
Box::default()
}
Expand Down

0 comments on commit dd0620b

Please sign in to comment.