diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index eb0e4c60200f..292fcf6f0d45 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -3036,7 +3036,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { ty: Ty<'db>, locals: &Locals<'a>, addr: Address, - _metadata: &[u8], + metadata: &[u8], span: MirSpan, ) -> Result<'db, ()> { let Some(drop_fn) = self.lang_items().Drop_drop else { @@ -3046,13 +3046,23 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { }; let generic_args = GenericArgs::new_from_slice(&[ty.into()]); - if let Ok(MirOrDynIndex::Mir(body)) = - self.get_mir_or_dyn_index(drop_fn, generic_args, locals, span) + let (drop_impl, drop_args) = self.db.lookup_impl_method( + ParamEnvAndCrate { param_env: self.param_env.param_env, krate: self.crate_id }, + drop_fn, + generic_args, + ); + if let Either::Left(drop_impl) = drop_impl + && matches!(drop_impl.lookup(self.db).container, ItemContainerId::ImplId(_)) + && let Ok(body) = self.db.monomorphized_mir_body( + drop_impl.into(), + drop_args.store(), + self.param_env.store(), + ) { self.exec_looked_up_function( body, locals, - drop_fn, + drop_impl, iter::once(IntervalOrOwned::Owned(addr.to_bytes().to_vec())), span, Interval { addr: Address::Invalid(0), size: 0 }, @@ -3093,6 +3103,12 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { AdtId::EnumId(_) => (), } } + TyKind::Dynamic(..) => { + if !metadata.is_empty() { + let concrete_ty = self.vtable_map.ty_of_bytes(metadata)?; + self.run_drop_glue_deep(concrete_ty, locals, addr, &[], span)?; + } + } TyKind::Bool | TyKind::Char | TyKind::Int(_) @@ -3115,7 +3131,6 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { | TyKind::Error(_) | TyKind::Param(_) | TyKind::Placeholder(_) - | TyKind::Dynamic(..) | TyKind::FnPtr(..) | TyKind::Bound(..) | TyKind::Infer(..) diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs index 0e94a5b92dd1..ccc4815d6cbc 100644 --- a/crates/hir-ty/src/mir/eval/tests.rs +++ b/crates/hir-ty/src/mir/eval/tests.rs @@ -229,6 +229,28 @@ fn main() { ); } +#[test] +fn drop_glue_for_type_without_drop_impl_does_not_recurse() { + check_pass( + r#" +//- minicore: drop, pin + +struct HasDrop; +impl Drop for HasDrop { + fn drop(&mut self) {} +} + +struct WithDropGlue { + field: HasDrop, +} + +fn main() { + let _c = WithDropGlue { field: HasDrop }; +} + "#, + ); +} + #[test] fn drop_if_let() { check_pass( @@ -358,6 +380,35 @@ fn main() { ); } +#[test] +fn drop_glue_for_trait_object() { + check_panic( + r#" +//- minicore: manually_drop, coerce_unsized, fmt, panic, drop, pin +use core::mem::ManuallyDrop; +use core::ptr::drop_in_place; + +struct X; +impl Drop for X { + fn drop(&mut self) { + panic!("concrete drop ran"); + } +} + +trait T {} +impl T for X {} + +fn main() { + let mut x = ManuallyDrop::new(X); + let p = &mut x as *mut ManuallyDrop as *mut X; + let obj: &mut dyn T = unsafe { &mut *p }; + drop_in_place(obj); +} + "#, + "concrete drop ran", + ); +} + #[test] fn manually_drop() { check_pass(