From 2af696d47b79f016e8c3444d14c494ea66568135 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 28 Jul 2025 01:12:05 -0700 Subject: [PATCH 1/2] Add a mir-opt pre-codegen test for dropping a `Box<[impl Copy]>` --- ..._in_place.PreCodegen.after.panic-abort.mir | 111 ++++++++++++++++++ ...in_place.PreCodegen.after.panic-unwind.mir | 111 ++++++++++++++++++ tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 17 +++ 3 files changed, 239 insertions(+) create mode 100644 tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir create mode 100644 tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir create mode 100644 tests/mir-opt/pre-codegen/drop_boxed_slice.rs diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir new file mode 100644 index 0000000000000..b06328dd6cbf4 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir @@ -0,0 +1,111 @@ +// MIR for `generic_in_place` after PreCodegen + +fn generic_in_place(_1: *mut Box<[T]>) -> () { + debug ptr => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box<[T]>))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull<[T]>; + let mut _3: *mut [T]; + let mut _4: *const [T]; + let _12: (); + scope 3 { + scope 4 { + scope 12 (inlined Layout::size) { + } + scope 13 (inlined Unique::<[T]>::cast::) { + scope 14 (inlined NonNull::<[T]>::cast::) { + scope 15 (inlined NonNull::<[T]>::as_ptr) { + } + } + } + scope 16 (inlined as From>>::from) { + scope 17 (inlined Unique::::as_non_null_ptr) { + } + } + scope 18 (inlined ::deallocate) { + let mut _8: *mut u8; + scope 19 (inlined Layout::size) { + } + scope 20 (inlined NonNull::::as_ptr) { + } + scope 21 (inlined std::alloc::dealloc) { + let mut _11: usize; + scope 22 (inlined Layout::size) { + } + scope 23 (inlined Layout::align) { + scope 24 (inlined std::ptr::Alignment::as_usize) { + let _9: std::ptr::alignment::AlignmentEnum; + let mut _10: u32; + } + } + } + } + } + scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 6 (inlined NonNull::<[T]>::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::<[T]>) { + let mut _5: usize; + let mut _6: usize; + scope 8 { + scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { + let mut _7: std::ptr::Alignment; + } + } + scope 9 (inlined size_of_val_raw::<[T]>) { + } + scope 10 (inlined align_of_val_raw::<[T]>) { + } + } + } + } + } + + bb0: { + StorageLive(_2); + _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); + StorageLive(_4); + _3 = copy _2 as *mut [T] (Transmute); + _4 = copy _2 as *const [T] (Transmute); + StorageLive(_6); + _5 = std::intrinsics::size_of_val::<[T]>(copy _4) -> [return: bb1, unwind unreachable]; + } + + bb1: { + _6 = std::intrinsics::align_of_val::<[T]>(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + _7 = copy _6 as std::ptr::Alignment (Transmute); + StorageDead(_6); + StorageDead(_4); + switchInt(copy _5) -> [0: bb5, otherwise: bb3]; + } + + bb3: { + StorageLive(_8); + _8 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_11); + StorageLive(_10); + StorageLive(_9); + _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _10 = discriminant(_9); + _11 = move _10 as usize (IntToInt); + StorageDead(_9); + StorageDead(_10); + _12 = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_11); + StorageDead(_8); + goto -> bb5; + } + + bb5: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir new file mode 100644 index 0000000000000..b06328dd6cbf4 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir @@ -0,0 +1,111 @@ +// MIR for `generic_in_place` after PreCodegen + +fn generic_in_place(_1: *mut Box<[T]>) -> () { + debug ptr => _1; + let mut _0: (); + scope 1 (inlined drop_in_place::> - shim(Some(Box<[T]>))) { + scope 2 (inlined as Drop>::drop) { + let _2: std::ptr::NonNull<[T]>; + let mut _3: *mut [T]; + let mut _4: *const [T]; + let _12: (); + scope 3 { + scope 4 { + scope 12 (inlined Layout::size) { + } + scope 13 (inlined Unique::<[T]>::cast::) { + scope 14 (inlined NonNull::<[T]>::cast::) { + scope 15 (inlined NonNull::<[T]>::as_ptr) { + } + } + } + scope 16 (inlined as From>>::from) { + scope 17 (inlined Unique::::as_non_null_ptr) { + } + } + scope 18 (inlined ::deallocate) { + let mut _8: *mut u8; + scope 19 (inlined Layout::size) { + } + scope 20 (inlined NonNull::::as_ptr) { + } + scope 21 (inlined std::alloc::dealloc) { + let mut _11: usize; + scope 22 (inlined Layout::size) { + } + scope 23 (inlined Layout::align) { + scope 24 (inlined std::ptr::Alignment::as_usize) { + let _9: std::ptr::alignment::AlignmentEnum; + let mut _10: u32; + } + } + } + } + } + scope 5 (inlined Unique::<[T]>::as_ptr) { + scope 6 (inlined NonNull::<[T]>::as_ptr) { + } + } + scope 7 (inlined Layout::for_value_raw::<[T]>) { + let mut _5: usize; + let mut _6: usize; + scope 8 { + scope 11 (inlined #[track_caller] Layout::from_size_align_unchecked) { + let mut _7: std::ptr::Alignment; + } + } + scope 9 (inlined size_of_val_raw::<[T]>) { + } + scope 10 (inlined align_of_val_raw::<[T]>) { + } + } + } + } + } + + bb0: { + StorageLive(_2); + _2 = copy (((*_1).0: std::ptr::Unique<[T]>).0: std::ptr::NonNull<[T]>); + StorageLive(_4); + _3 = copy _2 as *mut [T] (Transmute); + _4 = copy _2 as *const [T] (Transmute); + StorageLive(_6); + _5 = std::intrinsics::size_of_val::<[T]>(copy _4) -> [return: bb1, unwind unreachable]; + } + + bb1: { + _6 = std::intrinsics::align_of_val::<[T]>(move _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { + _7 = copy _6 as std::ptr::Alignment (Transmute); + StorageDead(_6); + StorageDead(_4); + switchInt(copy _5) -> [0: bb5, otherwise: bb3]; + } + + bb3: { + StorageLive(_8); + _8 = copy _3 as *mut u8 (PtrToPtr); + StorageLive(_11); + StorageLive(_10); + StorageLive(_9); + _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + _10 = discriminant(_9); + _11 = move _10 as usize (IntToInt); + StorageDead(_9); + StorageDead(_10); + _12 = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> [return: bb4, unwind unreachable]; + } + + bb4: { + StorageDead(_11); + StorageDead(_8); + goto -> bb5; + } + + bb5: { + StorageDead(_2); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs new file mode 100644 index 0000000000000..1ba1f27e15bf8 --- /dev/null +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -O -Zmir-opt-level=2 +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![crate_type = "lib"] +#![feature(step_trait)] + +// EMIT_MIR drop_boxed_slice.generic_in_place.PreCodegen.after.mir +pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { + // CHECK-LABEL: fn generic_in_place(_1: *mut Box<[T]>) + // CHECK: (inlined as Drop>::drop) + // CHECK: _7 = copy _6 as std::ptr::Alignment (Transmute); + // CHECK: _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); + // CHECK: _10 = discriminant(_9); + // CHECK: _11 = move _10 as usize (IntToInt); + // CHECK: = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> + std::ptr::drop_in_place(ptr) +} From 7ac4e0018ebecede8279bfd20fdb73a070c8becb Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Mon, 28 Jul 2025 01:03:49 -0700 Subject: [PATCH 2/2] Pass `Alignment` to the `__rust_*alloc*` shims --- library/alloc/src/alloc.rs | 18 ++++++++--------- tests/codegen-llvm/box-uninit-bytes.rs | 2 +- tests/codegen-llvm/vec-calloc.rs | 2 +- ..._in_place.PreCodegen.after.panic-abort.mir | 20 +++---------------- ...in_place.PreCodegen.after.panic-unwind.mir | 20 +++---------------- tests/mir-opt/pre-codegen/drop_boxed_slice.rs | 11 +++++----- 6 files changed, 23 insertions(+), 50 deletions(-) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index c9b98fa4e5a9b..f1fd6bec44825 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -6,7 +6,7 @@ #[doc(inline)] pub use core::alloc::*; use core::hint; -use core::ptr::{self, NonNull}; +use core::ptr::{self, Alignment, NonNull}; unsafe extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates @@ -17,19 +17,19 @@ unsafe extern "Rust" { #[rustc_allocator] #[rustc_nounwind] #[rustc_std_internal_symbol] - fn __rust_alloc(size: usize, align: usize) -> *mut u8; + fn __rust_alloc(size: usize, align: Alignment) -> *mut u8; #[rustc_deallocator] #[rustc_nounwind] #[rustc_std_internal_symbol] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); + fn __rust_dealloc(ptr: *mut u8, size: usize, align: Alignment); #[rustc_reallocator] #[rustc_nounwind] #[rustc_std_internal_symbol] - fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; + fn __rust_realloc(ptr: *mut u8, old_size: usize, align: Alignment, new_size: usize) -> *mut u8; #[rustc_allocator_zeroed] #[rustc_nounwind] #[rustc_std_internal_symbol] - fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; + fn __rust_alloc_zeroed(size: usize, align: Alignment) -> *mut u8; #[rustc_nounwind] #[rustc_std_internal_symbol] @@ -91,7 +91,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { // stable code until it is actually stabilized. __rust_no_alloc_shim_is_unstable_v2(); - __rust_alloc(layout.size(), layout.align()) + __rust_alloc(layout.size(), layout.alignment()) } } @@ -111,7 +111,7 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { - unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + unsafe { __rust_dealloc(ptr, layout.size(), layout.alignment()) } } /// Reallocates memory with the global allocator. @@ -131,7 +131,7 @@ pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } + unsafe { __rust_realloc(ptr, layout.size(), layout.alignment(), new_size) } } /// Allocates zero-initialized memory with the global allocator. @@ -174,7 +174,7 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { // stable code until it is actually stabilized. __rust_no_alloc_shim_is_unstable_v2(); - __rust_alloc_zeroed(layout.size(), layout.align()) + __rust_alloc_zeroed(layout.size(), layout.alignment()) } } diff --git a/tests/codegen-llvm/box-uninit-bytes.rs b/tests/codegen-llvm/box-uninit-bytes.rs index 0cc011485951c..f2b840dbb957e 100644 --- a/tests/codegen-llvm/box-uninit-bytes.rs +++ b/tests/codegen-llvm/box-uninit-bytes.rs @@ -41,6 +41,6 @@ pub fn box_lotsa_padding() -> Box { // Hide the `allocalign` attribute in the declaration of __rust_alloc // from the CHECK-NOT above, and also verify the attributes got set reasonably. -// CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] +// CHECK: declare {{(dso_local )?}}noalias noundef ptr @{{.*}}__rust_alloc(i{{[0-9]+}} noundef, i{{[0-9]+}} allocalign noundef range({{i64 1, -9223372036854775807|i32 1, -2147483647}})) unnamed_addr [[RUST_ALLOC_ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[RUST_ALLOC_ATTRS]] = { {{.*}} allockind("alloc,uninitialized,aligned") allocsize(0) {{(uwtable )?}}"alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/codegen-llvm/vec-calloc.rs b/tests/codegen-llvm/vec-calloc.rs index d1c320ead012e..9733673f4406e 100644 --- a/tests/codegen-llvm/vec-calloc.rs +++ b/tests/codegen-llvm/vec-calloc.rs @@ -177,6 +177,6 @@ pub fn vec_option_i32(n: usize) -> Vec> { } // Ensure that __rust_alloc_zeroed gets the right attributes for LLVM to optimize it away. -// CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] +// CHECK: declare noalias noundef ptr @{{.*}}__rust_alloc_zeroed(i64 noundef, i64 allocalign noundef range(i64 1, -9223372036854775807)) unnamed_addr [[RUST_ALLOC_ZEROED_ATTRS:#[0-9]+]] // CHECK-DAG: attributes [[RUST_ALLOC_ZEROED_ATTRS]] = { {{.*}} allockind("alloc,zeroed,aligned") allocsize(0) uwtable "alloc-family"="__rust_alloc" {{.*}} } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir index b06328dd6cbf4..09aaaad247334 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-abort.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _9: (); scope 3 { scope 4 { scope 12 (inlined Layout::size) { @@ -30,14 +30,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; scope 22 (inlined Layout::size) { } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { - let _9: std::ptr::alignment::AlignmentEnum; - let mut _10: u32; - } + scope 23 (inlined Layout::alignment) { } } } @@ -87,19 +82,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb3: { StorageLive(_8); _8 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); - StorageLive(_10); - StorageLive(_9); - _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _10 = discriminant(_9); - _11 = move _10 as usize (IntToInt); - StorageDead(_9); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> [return: bb4, unwind unreachable]; + _9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _7) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_11); StorageDead(_8); goto -> bb5; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir index b06328dd6cbf4..09aaaad247334 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.generic_in_place.PreCodegen.after.panic-unwind.mir @@ -8,7 +8,7 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { let _2: std::ptr::NonNull<[T]>; let mut _3: *mut [T]; let mut _4: *const [T]; - let _12: (); + let _9: (); scope 3 { scope 4 { scope 12 (inlined Layout::size) { @@ -30,14 +30,9 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { scope 20 (inlined NonNull::::as_ptr) { } scope 21 (inlined std::alloc::dealloc) { - let mut _11: usize; scope 22 (inlined Layout::size) { } - scope 23 (inlined Layout::align) { - scope 24 (inlined std::ptr::Alignment::as_usize) { - let _9: std::ptr::alignment::AlignmentEnum; - let mut _10: u32; - } + scope 23 (inlined Layout::alignment) { } } } @@ -87,19 +82,10 @@ fn generic_in_place(_1: *mut Box<[T]>) -> () { bb3: { StorageLive(_8); _8 = copy _3 as *mut u8 (PtrToPtr); - StorageLive(_11); - StorageLive(_10); - StorageLive(_9); - _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - _10 = discriminant(_9); - _11 = move _10 as usize (IntToInt); - StorageDead(_9); - StorageDead(_10); - _12 = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> [return: bb4, unwind unreachable]; + _9 = alloc::alloc::__rust_dealloc(move _8, move _5, move _7) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_11); StorageDead(_8); goto -> bb5; } diff --git a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs index 1ba1f27e15bf8..92c38574e60fd 100644 --- a/tests/mir-opt/pre-codegen/drop_boxed_slice.rs +++ b/tests/mir-opt/pre-codegen/drop_boxed_slice.rs @@ -8,10 +8,11 @@ pub unsafe fn generic_in_place(ptr: *mut Box<[T]>) { // CHECK-LABEL: fn generic_in_place(_1: *mut Box<[T]>) // CHECK: (inlined as Drop>::drop) - // CHECK: _7 = copy _6 as std::ptr::Alignment (Transmute); - // CHECK: _9 = copy (_7.0: std::ptr::alignment::AlignmentEnum); - // CHECK: _10 = discriminant(_9); - // CHECK: _11 = move _10 as usize (IntToInt); - // CHECK: = alloc::alloc::__rust_dealloc(move _8, move _5, move _11) -> + // CHECK: [[SIZE:_.+]] = std::intrinsics::size_of_val::<[T]> + // CHECK: [[ALIGN:_.+]] = std::intrinsics::align_of_val::<[T]> + // CHECK: [[ALIGNMENT:_.+]] = copy [[ALIGN]] as std::ptr::Alignment (Transmute); + // CHECK-NOT: discriminant + // CHECK-NOT: IntToInt + // CHECK: = alloc::alloc::__rust_dealloc({{.+}}, move [[SIZE]], move [[ALIGNMENT]]) -> std::ptr::drop_in_place(ptr) }