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
50 changes: 40 additions & 10 deletions compiler/rustc_mir_transform/src/elaborate_drop.rs
Copy link
Copy Markdown
Member

@bjorn3 bjorn3 May 12, 2026

Choose a reason for hiding this comment

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

The change in this file looks correct to me.

View changes since the review

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, GenericArg, GenericArgsRef, Ty, TyCtxt};
use rustc_middle::{bug, span_bug, traits};
use rustc_span::symbol::sym;
use rustc_span::{DUMMY_SP, Spanned, dummy_spanned};
use tracing::{debug, instrument};

Expand Down Expand Up @@ -973,26 +974,55 @@ where
fn destructor_call_block_sync(&mut self, succ: BasicBlock, unwind: Unwind) -> BasicBlock {
let tcx = self.tcx();
let drop_trait = tcx.require_lang_item(LangItem::Drop, DUMMY_SP);
let drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let mut drop_fn = tcx.associated_item_def_ids(drop_trait)[0];
let ty = self.place_ty(self.place);

let ref_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, ty);
let ref_place = self.new_temp(ref_ty);
let unit_temp = Place::from(self.new_temp(tcx.types.unit));

let mut arg_place = ref_place;

let mut stmts = vec![self.assign(
Place::from(ref_place),
Rvalue::Ref(
tcx.lifetimes.re_erased,
BorrowKind::Mut { kind: MutBorrowKind::Default },
self.place,
),
)];

// When the type implements `Drop::pin_drop`, we call it directly instead of `Drop::drop`.
if let Some(adt) = ty.ty_adt_def()
&& let Some(dtor) = adt.destructor(tcx)
&& tcx.item_name(dtor.did) == sym::pin_drop
{
debug!("call `pin_drop` for {adt:?}");
let pin_ref_ty = Ty::new_pinned_ref(tcx, tcx.lifetimes.re_erased, ty, Mutability::Mut);
let pin_ref_place = self.new_temp(pin_ref_ty);
stmts.push(self.assign(
Place::from(pin_ref_place),
Rvalue::Aggregate(
Box::new(AggregateKind::Adt(
tcx.require_lang_item(LangItem::Pin, DUMMY_SP),
VariantIdx::ZERO,
tcx.mk_args(&[ref_ty.into()]),
None,
None,
)),
[Operand::Move(Place::from(ref_place))].into(),
),
));
drop_fn = tcx.associated_item_def_ids(drop_trait)[1];
arg_place = pin_ref_place;
}

self.new_block_with_statements(
unwind,
vec![self.assign(
Place::from(ref_place),
Rvalue::Ref(
tcx.lifetimes.re_erased,
BorrowKind::Mut { kind: MutBorrowKind::Default },
self.place,
),
)],
stmts,
TerminatorKind::Call {
func: Operand::function_handle(tcx, drop_fn, [ty.into()], self.source_info.span),
args: [Spanned { node: Operand::Move(Place::from(ref_place)), span: DUMMY_SP }]
args: [Spanned { node: Operand::Move(Place::from(arg_place)), span: DUMMY_SP }]
.into(),
destination: unit_temp,
target: Some(succ),
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,15 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) ->
tcx.dcx().delayed_bug("attempt to codegen `#[rustc_force_inline]` item");
}

// It is not possible to manually call `Drop::drop` and `Drop::pin_drop`, so we can
// skip codegen for mentioned associated items of the `Drop` trait, and only codegen
// `drop` or `pin_drop` depending on which was implemented.
if let Some(trait_id) = tcx.trait_of_assoc(def_id)
&& tcx.is_lang_item(trait_id, LangItem::Drop)
{
return false;
Copy link
Copy Markdown
Contributor Author

@frank-king frank-king May 12, 2026

Choose a reason for hiding this comment

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

Like the #[rustc_force_inline] case above, I expect Drop::drop and Drop::pin_drop should never be codegened, so I tried emitting a delayed bug, but all the codegen-units tests related to drop glue failed.

I've also tried to add #[rustc_force_inline] to Drop::drop (with trait method attribute target allowed), but core could not even be built where the debug_assert_matches failed at ForceInliner::check_codegen_attributes_extra.

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Either Drop::drop or Drop::pin_drop would need to be codegened for the drop glue to call, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's true, but the root item Drop::drop or Drop::pin_drop has been collected by collect_items_root, which is not guarded by should_codegen_locally, right?

}

if def_id.is_local() {
// Local items cannot be referred to locally without monomorphizing them locally.
return true;
Expand Down
4 changes: 0 additions & 4 deletions tests/codegen-units/item-collection/drop-glue-eager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ struct StructWithDrop {

impl Drop for StructWithDrop {
//~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::drop
//~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand All @@ -25,7 +24,6 @@ enum EnumWithDrop {

impl Drop for EnumWithDrop {
//~ MONO_ITEM fn <EnumWithDrop as std::ops::Drop>::drop
//~ MONO_ITEM fn <EnumWithDrop as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand All @@ -36,7 +34,6 @@ enum EnumNoDrop {
// We should be able to monomorphize drops for struct with lifetimes.
impl<'a> Drop for StructWithDropAndLt<'a> {
//~ MONO_ITEM fn <StructWithDropAndLt<'_> as std::ops::Drop>::drop
//~ MONO_ITEM fn <StructWithDropAndLt<'_> as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand All @@ -55,6 +52,5 @@ struct StructWithLtAndPredicate<'a: 'a> {
// We should be able to monomorphize drops for struct with lifetimes.
impl<'a> Drop for StructWithLtAndPredicate<'a> {
//~ MONO_ITEM fn <StructWithLtAndPredicate<'_> as std::ops::Drop>::drop
//~ MONO_ITEM fn <StructWithLtAndPredicate<'_> as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ struct StructWithDtor(u32);

impl Drop for StructWithDtor {
//~ MONO_ITEM fn <StructWithDtor as std::ops::Drop>::drop
//~ MONO_ITEM fn <StructWithDtor as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}
//~ MONO_ITEM fn start
Expand Down
1 change: 0 additions & 1 deletion tests/codegen-units/item-collection/generic-drop-glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ struct NonGenericWithDrop(#[allow(dead_code)] i32);

impl Drop for NonGenericWithDrop {
//~ MONO_ITEM fn <NonGenericWithDrop as std::ops::Drop>::drop
//~ MONO_ITEM fn <NonGenericWithDrop as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,5 @@ struct PresentDrop;

impl Drop for PresentDrop {
//~ MONO_ITEM fn <PresentDrop as std::ops::Drop>::drop @@ non_generic_closures-cgu.0[External]
//~ MONO_ITEM fn <PresentDrop as std::ops::Drop>::pin_drop @@ non_generic_closures-cgu.0[External]
fn drop(&mut self) {}
}
2 changes: 0 additions & 2 deletions tests/codegen-units/item-collection/non-generic-drop-glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ struct StructWithDrop {

impl Drop for StructWithDrop {
//~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::drop
//~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand All @@ -26,7 +25,6 @@ enum EnumWithDrop {

impl Drop for EnumWithDrop {
//~ MONO_ITEM fn <EnumWithDrop as std::ops::Drop>::drop
//~ MONO_ITEM fn <EnumWithDrop as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand Down
41 changes: 41 additions & 0 deletions tests/codegen-units/item-collection/pin-drop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#![feature(pin_ergonomics)]
// Ensure that we emit either `Drop::drop` or `Drop::pin_drop` for types that implement `Drop`.

//@ compile-flags:-Clink-dead-code
//@ compile-flags:--crate-type=lib
//@ rustc-env:MONO_TEST=1

//~ MONO_ITEM fn std::ptr::drop_glue::<StructWithDrop> - shim(Some(StructWithDrop))
struct StructWithDrop {
x: i32,
}

impl Drop for StructWithDrop {
//~ MONO_ITEM fn <StructWithDrop as std::ops::Drop>::drop
fn drop(&mut self) {}
}

struct StructNoDrop {
x: i32,
}

//~ MONO_ITEM fn std::ptr::drop_glue::<StructWithPinDrop> - shim(Some(StructWithPinDrop))
struct StructWithPinDrop {
x: i32,
}

impl Drop for StructWithPinDrop {
//~ MONO_ITEM fn <StructWithPinDrop as std::ops::Drop>::pin_drop
fn pin_drop(&pin mut self) {}
}

//~ MONO_ITEM fn std::ptr::drop_glue::<StructPinV2WithPinDrop> - shim(Some(StructPinV2WithPinDrop))
#[pin_v2]
struct StructPinV2WithPinDrop {
x: i32,
}

impl Drop for StructPinV2WithPinDrop {
//~ MONO_ITEM fn <StructPinV2WithPinDrop as std::ops::Drop>::pin_drop
fn pin_drop(&pin mut self) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ struct Leaf;

impl Drop for Leaf {
//~ MONO_ITEM fn <Leaf as std::ops::Drop>::drop
//~ MONO_ITEM fn <Leaf as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand Down
1 change: 0 additions & 1 deletion tests/codegen-units/item-collection/tuple-drop-glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ struct Dropped;

impl Drop for Dropped {
//~ MONO_ITEM fn <Dropped as std::ops::Drop>::drop
//~ MONO_ITEM fn <Dropped as std::ops::Drop>::pin_drop
fn drop(&mut self) {}
}

Expand Down
Loading