From 05f52c7a9907fd63972d2030d1d42042904d9a9e Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 11 Apr 2026 21:35:23 -0700 Subject: [PATCH 1/2] Have arrays' `drop_glue` just unsize and call the slice version --- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 44 +++++++++++- tests/codegen-llvm/array-drop-glue.rs | 67 +++++++++++++++++++ ...ring;42].AddMovesForPackedDrops.before.mir | 54 +-------------- 4 files changed, 113 insertions(+), 54 deletions(-) create mode 100644 tests/codegen-llvm/array-drop-glue.rs diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1d761c2f43b3d..b81e0b6f3471a 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -292,7 +292,7 @@ impl<'tcx> InstanceKind<'tcx> { use rustc_hir::definitions::DefPathData; let def_id = match *self { ty::InstanceKind::Item(def) => def, - ty::InstanceKind::DropGlue(_, Some(_)) => return false, + ty::InstanceKind::DropGlue(_, Some(ty)) => return ty.is_array(), ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => return ty.is_coroutine(), ty::InstanceKind::FutureDropPollShim(_, _, _) => return false, ty::InstanceKind::AsyncDropGlue(_, _) => return false, diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 459d87d74cd7b..7f92199dec455 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -317,16 +317,56 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) let block = |blocks: &mut IndexVec<_, _>, kind| { blocks.push(BasicBlockData::new(Some(Terminator { source_info, kind }), false)) }; - block(&mut blocks, TerminatorKind::Goto { target: return_block }); + if ty.is_some() { + block(&mut blocks, TerminatorKind::Goto { target: return_block }); + } block(&mut blocks, TerminatorKind::Return); let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty)); let mut body = new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); + let Some(ty) = ty else { + return body; + }; + let dropee_ptr = Place::from(Local::arg(0)); - if ty.is_some() { + if let ty::Array(ety, _len) = *ty.kind() { + // Don't write out the elaboration for each array type. + // Instead, just delegate to the slice version. + let slice_ty = Ty::new_slice(tcx, ety); + let mut_slice_ty = Ty::new_ref(tcx, tcx.lifetimes.re_erased, slice_ty, ty::Mutability::Mut); + let erased_local = body.local_decls.push(LocalDecl::new(mut_slice_ty, span)); + + let start = &mut body.basic_blocks_mut()[START_BLOCK]; + start.statements.push(Statement::new( + source_info, + StatementKind::Assign(Box::new(( + Place::from(erased_local), + Rvalue::Cast( + CastKind::PointerCoercion( + ty::adjustment::PointerCoercion::Unsize, + CoercionSource::Implicit, + ), + Operand::Move(dropee_ptr), + mut_slice_ty, + ), + ))), + )); + start.terminator = Some(Terminator { + source_info, + kind: TerminatorKind::Call { + func: Operand::function_handle(tcx, def_id, [ty::GenericArg::from(slice_ty)], span), + args: Box::new([Spanned { span, node: Operand::Move(Place::from(erased_local)) }]), + destination: Place::from(RETURN_PLACE), + target: Some(return_block), + unwind: UnwindAction::Continue, + call_source: CallSource::Misc, + fn_span: span, + }, + }); + } else { let patch = { let typing_env = ty::TypingEnv::post_analysis(tcx, def_id); let mut elaborator = DropShimElaborator { diff --git a/tests/codegen-llvm/array-drop-glue.rs b/tests/codegen-llvm/array-drop-glue.rs new file mode 100644 index 0000000000000..994879cb65cf1 --- /dev/null +++ b/tests/codegen-llvm/array-drop-glue.rs @@ -0,0 +1,67 @@ +//@ revisions: RAW OPT +//@ compile-flags: -C opt-level=z -C panic=abort +//@[RAW] compile-flags: -C no-prepopulate-passes -Z inline-mir + +#![crate_type = "lib"] + +// Ensure all the different array drop_glue functions just delegate to the slice one, +// rather than emitting two loops in each of the three. + +// When this test was first written, the array drop glues came out in the +// seemingly-arbitrary order of 42, then 7, then 13, so to avoid potential +// fragility from that changing we don't check any particular order. + +// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> +// RAW-NEXT: inlinehint +// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> +// RAW-NEXT: noundef [[N]]) +// RAW: } + +// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> +// RAW-NEXT: inlinehint +// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> +// RAW-NEXT: noundef [[N]]) +// RAW: } + +// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> +// RAW-NEXT: inlinehint +// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> +// RAW-NEXT: noundef [[N]]) +// RAW: } + +// CHECK-LABEL: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> +// CHECK-NOT: inlinehint +// OPT: add nuw nsw {{.+}} 1 +// CHECK: } + +#[no_mangle] +// CHECK-LABEL: @drop_arrays +pub fn drop_arrays(x: [NeedsDrop; 7], y: [NeedsDrop; 13], z: [NeedsDrop; 42]) { + // I don't remember the parameter drop order, so write out the order the test expects. + + // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 7]> + // OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> + // OPT-NEXT: noundef 7) + drop(x); + // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 13]> + // OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> + // OPT-NEXT: noundef 13) + drop(y); + // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; 42]> + // OPT: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> + // OPT-NEXT: noundef 42) + drop(z); +} + +struct NeedsDrop(u32); + +impl Drop for NeedsDrop { + #[inline] + fn drop(&mut self) { + do_the_drop(self); + } +} + +unsafe extern "Rust" { + safe fn do_the_drop(_: &mut NeedsDrop); +} diff --git a/tests/mir-opt/slice_drop_shim.core.ptr-drop_glue.[String;42].AddMovesForPackedDrops.before.mir b/tests/mir-opt/slice_drop_shim.core.ptr-drop_glue.[String;42].AddMovesForPackedDrops.before.mir index 66591dcc91df2..1d4b0f033e0be 100644 --- a/tests/mir-opt/slice_drop_shim.core.ptr-drop_glue.[String;42].AddMovesForPackedDrops.before.mir +++ b/tests/mir-opt/slice_drop_shim.core.ptr-drop_glue.[String;42].AddMovesForPackedDrops.before.mir @@ -2,62 +2,14 @@ fn std::ptr::drop_glue(_1: &mut [String; 42]) -> () { let mut _0: (); - let mut _2: *mut [std::string::String; 42]; - let mut _3: *mut [std::string::String]; - let mut _4: usize; - let mut _5: usize; - let mut _6: *mut std::string::String; - let mut _7: bool; - let mut _8: *mut std::string::String; - let mut _9: bool; + let mut _2: &mut [std::string::String]; bb0: { - goto -> bb9; + _2 = move _1 as &mut [std::string::String] (PointerCoercion(Unsize, Implicit)); + _0 = std::ptr::drop_glue::<[String]>(move _2) -> [return: bb1, unwind continue]; } bb1: { return; } - - bb2 (cleanup): { - resume; - } - - bb3 (cleanup): { - _6 = &raw mut (*_3)[_5]; - _5 = Add(move _5, const 1_usize); - drop((*_6)) -> [return: bb4, unwind terminate(cleanup)]; - } - - bb4 (cleanup): { - _7 = Eq(copy _5, copy _4); - switchInt(move _7) -> [0: bb3, otherwise: bb2]; - } - - bb5: { - _8 = &raw mut (*_3)[_5]; - _5 = Add(move _5, const 1_usize); - drop((*_8)) -> [return: bb6, unwind: bb4]; - } - - bb6: { - _9 = Eq(copy _5, copy _4); - switchInt(move _9) -> [0: bb5, otherwise: bb1]; - } - - bb7: { - _4 = PtrMetadata(copy _3); - _5 = const 0_usize; - goto -> bb6; - } - - bb8: { - goto -> bb7; - } - - bb9: { - _2 = &raw mut (*_1); - _3 = move _2 as *mut [std::string::String] (PointerCoercion(Unsize, Implicit)); - goto -> bb8; - } } From b0020c93ee88676e8dfdf6d027f6db61fefe5892 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 9 May 2026 01:07:49 -0700 Subject: [PATCH 2/2] [For Comparison] What if we don't touch inlining? --- compiler/rustc_middle/src/ty/instance.rs | 2 +- tests/codegen-llvm/array-drop-glue.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index b81e0b6f3471a..1d761c2f43b3d 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -292,7 +292,7 @@ impl<'tcx> InstanceKind<'tcx> { use rustc_hir::definitions::DefPathData; let def_id = match *self { ty::InstanceKind::Item(def) => def, - ty::InstanceKind::DropGlue(_, Some(ty)) => return ty.is_array(), + ty::InstanceKind::DropGlue(_, Some(_)) => return false, ty::InstanceKind::AsyncDropGlueCtorShim(_, ty) => return ty.is_coroutine(), ty::InstanceKind::FutureDropPollShim(_, _, _) => return false, ty::InstanceKind::AsyncDropGlue(_, _) => return false, diff --git a/tests/codegen-llvm/array-drop-glue.rs b/tests/codegen-llvm/array-drop-glue.rs index 994879cb65cf1..f8bea8f8bd4ac 100644 --- a/tests/codegen-llvm/array-drop-glue.rs +++ b/tests/codegen-llvm/array-drop-glue.rs @@ -12,19 +12,19 @@ // fragility from that changing we don't check any particular order. // RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> -// RAW-NEXT: inlinehint +// RAW-NOT: inlinehint // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> // RAW-NEXT: noundef [[N]]) // RAW: } // RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> -// RAW-NEXT: inlinehint +// RAW-NOT: inlinehint // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> // RAW-NEXT: noundef [[N]]) // RAW: } // RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]> -// RAW-NEXT: inlinehint +// RAW-NOT: inlinehint // RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]> // RAW-NEXT: noundef [[N]]) // RAW: }