Skip to content

Commit 2f4ef71

Browse files
committed
allocate before calling T::default in <Box<T>>::default()
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.
1 parent 9af70c1 commit 2f4ef71

File tree

2 files changed

+3
-3
lines changed

2 files changed

+3
-3
lines changed

Diff for: library/alloc/src/boxed.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1688,7 +1688,7 @@ impl<T: Default> Default for Box<T> {
16881688
/// Creates a `Box<T>`, with the `Default` value for T.
16891689
#[inline]
16901690
fn default() -> Self {
1691-
Box::new(T::default())
1691+
Box::write(Box::new_uninit(), T::default())
16921692
}
16931693
}
16941694

Diff for: tests/codegen/placement-new.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ use std::sync::Arc;
99
// CHECK-LABEL: @box_default_inplace
1010
#[no_mangle]
1111
pub fn box_default_inplace() -> Box<(String, String)> {
12-
// CHECK: [[ALLOCA:%.*]] = alloca
12+
// CHECK-NOT: alloca
1313
// CHECK: [[BOX:%.*]] = {{.*}}call {{.*}}__rust_alloc(
14-
// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}[[BOX]], ptr {{.*}}[[ALLOCA]]
14+
// CHECK-NOT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}[[BOX]],
1515
// CHECK: ret ptr [[BOX]]
1616
Box::default()
1717
}

0 commit comments

Comments
 (0)