Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 42 additions & 2 deletions compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,16 +317,56 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
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 {
Expand Down
67 changes: 67 additions & 0 deletions tests/codegen-llvm/array-drop-glue.rs
Original file line number Diff line number Diff line change
@@ -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-NOT: inlinehint
// RAW: call core::ptr::drop_glue::<[array_drop_glue::NeedsDrop]>
Copy link
Copy Markdown
Member Author

@scottmcm scottmcm Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View changes since the review

Compare nightly https://rust.godbolt.org/z/5Wv1q86ja with a loop in each of the three.

// RAW-NEXT: noundef [[N]])
// RAW: }

// RAW: ; core::ptr::drop_glue::<[array_drop_glue::NeedsDrop; [[N:7|13|42]]]>
// 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-NOT: 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}