about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-02-23 03:34:33 +0000
committerMichael Goulet <michael@errs.io>2025-02-26 19:03:29 +0000
commit864cca80b02e9daa2c41440f1bf9787083c9f149 (patch)
tree78e799a2e33877a4f8369e44bf5c6aca66b97044
parentac91805f3179fc2225c60e8ccf5a1daa09d43f3d (diff)
downloadrust-864cca80b02e9daa2c41440f1bf9787083c9f149.tar.gz
rust-864cca80b02e9daa2c41440f1bf9787083c9f149.zip
Print out destructor
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/messages.ftl5
-rw-r--r--compiler/rustc_lint/src/if_let_rescope.rs77
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/significant_drop_order.rs172
-rw-r--r--compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs174
-rw-r--r--tests/ui/drop/drop-order-comparisons.e2021.stderr90
-rw-r--r--tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr9
-rw-r--r--tests/ui/drop/lint-if-let-rescope-with-macro.stderr9
-rw-r--r--tests/ui/drop/lint-if-let-rescope.stderr72
11 files changed, 425 insertions, 186 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fb4cf235c6f..2227f5f3e99 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3916,6 +3916,7 @@ dependencies = [
  "rustc_target",
  "rustc_trait_selection",
  "rustc_type_ir",
+ "smallvec",
  "tracing",
  "unicode-security",
 ]
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 24e7b40c8a2..d6014f5006a 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -24,6 +24,7 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
 rustc_type_ir = { path = "../rustc_type_ir" }
+smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 unicode-security = "0.1.0"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 67936763427..d51865810b9 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -333,6 +333,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
         *[other] {" "}{$identifier_type}
     } Unicode general security profile
 
+lint_if_let_dtor = {$dtor_kind ->
+    [dyn] value may invoke a custom destructor because it contains a trait object
+    *[concrete] value invokes this custom destructor
+    }
+
 lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
     .label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
     .help = the value is now dropped here in Edition 2024
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 23f037f3692..39ea8d8e324 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -7,13 +7,17 @@ use rustc_errors::{
     Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
 };
 use rustc_hir::{self as hir, HirIdSet};
-use rustc_macros::LintDiagnostic;
-use rustc_middle::ty::TyCtxt;
+use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::adjustment::Adjust;
+use rustc_middle::ty::significant_drop_order::{
+    extract_component_with_significant_dtor, ty_dtor_span,
+};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint::{FutureIncompatibilityReason, LintId};
 use rustc_session::{declare_lint, impl_lint_pass};
-use rustc_span::Span;
 use rustc_span::edition::Edition;
+use rustc_span::{DUMMY_SP, Span};
+use smallvec::SmallVec;
 
 use crate::{LateContext, LateLintPass};
 
@@ -130,6 +134,7 @@ impl IfLetRescope {
             hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
             _ => return,
         };
+        let mut seen_dyn = false;
         let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
         let mut significant_droppers = vec![];
         let mut lifetime_ends = vec![];
@@ -137,6 +142,7 @@ impl IfLetRescope {
         let mut alt_heads = vec![];
         let mut match_heads = vec![];
         let mut consequent_heads = vec![];
+        let mut destructors = vec![];
         let mut first_if_to_lint = None;
         let mut first_if_to_rewrite = false;
         let mut empty_alt = false;
@@ -160,11 +166,25 @@ impl IfLetRescope {
                 let before_conseq = conseq.span.shrink_to_lo();
                 let lifetime_end = source_map.end_point(conseq.span);
 
-                if let ControlFlow::Break(significant_dropper) =
+                if let ControlFlow::Break((drop_span, drop_tys)) =
                     (FindSignificantDropper { cx }).check_if_let_scrutinee(init)
                 {
+                    destructors.extend(drop_tys.into_iter().filter_map(|ty| {
+                        if let Some(span) = ty_dtor_span(tcx, ty) {
+                            Some(DestructorLabel { span, dtor_kind: "concrete" })
+                        } else if matches!(ty.kind(), ty::Dynamic(..)) {
+                            if seen_dyn {
+                                None
+                            } else {
+                                seen_dyn = true;
+                                Some(DestructorLabel { span: DUMMY_SP, dtor_kind: "dyn" })
+                            }
+                        } else {
+                            None
+                        }
+                    }));
                     first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id)));
-                    significant_droppers.push(significant_dropper);
+                    significant_droppers.push(drop_span);
                     lifetime_ends.push(lifetime_end);
                     if ty_ascription.is_some()
                         || !expr.span.can_be_used_for_suggestions()
@@ -227,6 +247,7 @@ impl IfLetRescope {
                 hir_id,
                 span,
                 IfLetRescopeLint {
+                    destructors,
                     significant_droppers,
                     lifetime_ends,
                     rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite {
@@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
 #[derive(LintDiagnostic)]
 #[diag(lint_if_let_rescope)]
 struct IfLetRescopeLint {
+    #[subdiagnostic]
+    destructors: Vec<DestructorLabel>,
     #[label]
     significant_droppers: Vec<Span>,
     #[help]
@@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
     }
 }
 
+#[derive(Subdiagnostic)]
+#[note(lint_if_let_dtor)]
+struct DestructorLabel {
+    #[primary_span]
+    span: Span,
+    dtor_kind: &'static str,
+}
+
 struct AltHead(Span);
 
 struct ConsequentRewrite {
@@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
     /// of the scrutinee itself, and also recurses into the expression to find any ref
     /// exprs (or autoref) which would promote temporaries that would be scoped to the
     /// end of this `if`.
-    fn check_if_let_scrutinee(&mut self, init: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
+    fn check_if_let_scrutinee(
+        &mut self,
+        init: &'tcx hir::Expr<'tcx>,
+    ) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
         self.check_promoted_temp_with_drop(init)?;
         self.visit_expr(init)
     }
@@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
     /// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
     /// or is the scrutinee of the `if let`, *and* the expression is not a place
     /// expr, and it has a significant drop.
-    fn check_promoted_temp_with_drop(&self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
-        if !expr.is_place_expr(|base| {
+    fn check_promoted_temp_with_drop(
+        &self,
+        expr: &'tcx hir::Expr<'tcx>,
+    ) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
+        if expr.is_place_expr(|base| {
             self.cx
                 .typeck_results()
                 .adjustments()
                 .get(base.hir_id)
                 .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
-        }) && self
-            .cx
-            .typeck_results()
-            .expr_ty(expr)
-            .has_significant_drop(self.cx.tcx, self.cx.typing_env())
-        {
-            ControlFlow::Break(expr.span)
-        } else {
-            ControlFlow::Continue(())
+        }) {
+            return ControlFlow::Continue(());
         }
+
+        let drop_tys = extract_component_with_significant_dtor(
+            self.cx.tcx,
+            self.cx.typing_env(),
+            self.cx.typeck_results().expr_ty(expr),
+        );
+        if drop_tys.is_empty() {
+            return ControlFlow::Continue(());
+        }
+
+        ControlFlow::Break((expr.span, drop_tys))
     }
 }
 
 impl<'tcx> Visitor<'tcx> for FindSignificantDropper<'_, 'tcx> {
-    type Result = ControlFlow<Span>;
+    type Result = ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)>;
 
     fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result {
         // Blocks introduce temporary terminating scope for all of its
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index eb70a35d370..d926d6cc02a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -122,6 +122,7 @@ pub mod normalize_erasing_regions;
 pub mod pattern;
 pub mod print;
 pub mod relate;
+pub mod significant_drop_order;
 pub mod trait_def;
 pub mod util;
 pub mod visit;
diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs
new file mode 100644
index 00000000000..7f0d82d89fe
--- /dev/null
+++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs
@@ -0,0 +1,172 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::unord::UnordSet;
+use rustc_hir::def_id::DefId;
+use rustc_span::Span;
+use smallvec::{SmallVec, smallvec};
+use tracing::{debug, instrument};
+
+use crate::ty::{self, Ty, TyCtxt};
+
+/// An additional filter to exclude well-known types from the ecosystem
+/// because their drops are trivial.
+/// This returns additional types to check if the drops are delegated to those.
+/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
+fn true_significant_drop_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
+    if let ty::Adt(def, args) = ty.kind() {
+        let mut did = def.did();
+        let mut name_rev = vec![];
+        loop {
+            let key = tcx.def_key(did);
+
+            match key.disambiguated_data.data {
+                rustc_hir::definitions::DefPathData::CrateRoot => {
+                    name_rev.push(tcx.crate_name(did.krate))
+                }
+                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
+                _ => return None,
+            }
+            if let Some(parent) = key.parent {
+                did = DefId { krate: did.krate, index: parent };
+            } else {
+                break;
+            }
+        }
+        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
+        debug!(?name_str);
+        match name_str[..] {
+            // These are the types from Rust core ecosystem
+            ["syn" | "proc_macro2", ..]
+            | ["core" | "std", "task", "LocalWaker" | "Waker"]
+            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
+            // These are important types from Rust ecosystem
+            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
+            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
+                if let [ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            ["hashbrown", "raw", "RawDrain"] => {
+                if let [_, ty, ..] = &***args
+                    && let Some(ty) = ty.as_type()
+                {
+                    Some(smallvec![ty])
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
+
+/// Returns the list of types with a "potentially sigificant" that may be dropped
+/// by dropping a value of type `ty`.
+#[instrument(level = "trace", skip(tcx, typing_env))]
+pub fn extract_component_raw<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+    ty_seen: &mut UnordSet<Ty<'tcx>>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    // Droppiness does not depend on regions, so let us erase them.
+    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+
+    let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
+    debug!(?ty, "components");
+    let mut out_tys = smallvec![];
+    for ty in tys {
+        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
+            // Some types can be further opened up because the drop is simply delegated
+            for ty in tys {
+                if ty_seen.insert(ty) {
+                    out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
+                }
+            }
+        } else {
+            if ty_seen.insert(ty) {
+                out_tys.push(ty);
+            }
+        }
+    }
+    out_tys
+}
+
+#[instrument(level = "trace", skip(tcx, typing_env))]
+pub fn extract_component_with_significant_dtor<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: ty::TypingEnv<'tcx>,
+    ty: Ty<'tcx>,
+) -> SmallVec<[Ty<'tcx>; 4]> {
+    let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
+    let mut deduplicate = FxHashSet::default();
+    tys.retain(|oty| deduplicate.insert(*oty));
+    tys.into_iter().collect()
+}
+
+/// Extract the span of the custom destructor of a type
+/// especially the span of the `impl Drop` header or its entire block
+/// when we are working with current local crate.
+#[instrument(level = "trace", skip(tcx))]
+pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
+    match ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Error(_)
+        | ty::Str
+        | ty::Never
+        | ty::RawPtr(_, _)
+        | ty::Ref(_, _, _)
+        | ty::FnPtr(_, _)
+        | ty::Tuple(_)
+        | ty::Dynamic(_, _, _)
+        | ty::Alias(_, _)
+        | ty::Bound(_, _)
+        | ty::Pat(_, _)
+        | ty::Placeholder(_)
+        | ty::Infer(_)
+        | ty::Slice(_)
+        | ty::Array(_, _)
+        | ty::UnsafeBinder(_) => None,
+
+        ty::Adt(adt_def, _) => {
+            let did = adt_def.did();
+            let try_local_did_span = |did: DefId| {
+                if let Some(local) = did.as_local() {
+                    tcx.source_span(local)
+                } else {
+                    tcx.def_span(did)
+                }
+            };
+            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
+                dtor.did
+            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
+                dtor.future
+            } else {
+                return Some(try_local_did_span(did));
+            };
+            let def_key = tcx.def_key(dtor);
+            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
+            let parent_did = DefId { index: parent_index, krate: dtor.krate };
+            Some(try_local_did_span(parent_did))
+        }
+        ty::Coroutine(did, _)
+        | ty::CoroutineWitness(did, _)
+        | ty::CoroutineClosure(did, _)
+        | ty::Closure(did, _)
+        | ty::FnDef(did, _)
+        | ty::Foreign(did) => Some(tcx.def_span(did)),
+        ty::Param(_) => None,
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index e3260e45bc5..7d77fffa83f 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::Subdiagnostic;
 use rustc_hir::CRATE_HIR_ID;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
 use rustc_index::bit_set::MixedBitSet;
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
@@ -15,7 +15,10 @@ use rustc_middle::mir::{
     self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind,
     dump_mir,
 };
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::significant_drop_order::{
+    extract_component_with_significant_dtor, ty_dtor_span,
+};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor};
@@ -23,8 +26,7 @@ use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER;
 use rustc_session::lint::{self};
 use rustc_span::{DUMMY_SP, Span, Symbol};
 use rustc_type_ir::data_structures::IndexMap;
-use smallvec::{SmallVec, smallvec};
-use tracing::{debug, instrument};
+use tracing::debug;
 
 fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool {
     left.local == right.local
@@ -155,170 +157,6 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
     }
 }
 
-/// An additional filter to exclude well-known types from the ecosystem
-/// because their drops are trivial.
-/// This returns additional types to check if the drops are delegated to those.
-/// A typical example is `hashbrown::HashMap<K, V>`, whose drop is delegated to `K` and `V`.
-fn true_significant_drop_ty<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<SmallVec<[Ty<'tcx>; 2]>> {
-    if let ty::Adt(def, args) = ty.kind() {
-        let mut did = def.did();
-        let mut name_rev = vec![];
-        loop {
-            let key = tcx.def_key(did);
-
-            match key.disambiguated_data.data {
-                rustc_hir::definitions::DefPathData::CrateRoot => {
-                    name_rev.push(tcx.crate_name(did.krate))
-                }
-                rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol),
-                _ => return None,
-            }
-            if let Some(parent) = key.parent {
-                did = DefId { krate: did.krate, index: parent };
-            } else {
-                break;
-            }
-        }
-        let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect();
-        debug!(?name_str);
-        match name_str[..] {
-            // These are the types from Rust core ecosystem
-            ["syn" | "proc_macro2", ..]
-            | ["core" | "std", "task", "LocalWaker" | "Waker"]
-            | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]),
-            // These are important types from Rust ecosystem
-            ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]),
-            ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => {
-                if let [ty, ..] = &***args
-                    && let Some(ty) = ty.as_type()
-                {
-                    Some(smallvec![ty])
-                } else {
-                    None
-                }
-            }
-            ["hashbrown", "raw", "RawDrain"] => {
-                if let [_, ty, ..] = &***args
-                    && let Some(ty) = ty.as_type()
-                {
-                    Some(smallvec![ty])
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        }
-    } else {
-        None
-    }
-}
-
-/// Returns the list of types with a "potentially sigificant" that may be dropped
-/// by dropping a value of type `ty`.
-#[instrument(level = "debug", skip(tcx, typing_env))]
-fn extract_component_raw<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    typing_env: ty::TypingEnv<'tcx>,
-    ty: Ty<'tcx>,
-    ty_seen: &mut UnordSet<Ty<'tcx>>,
-) -> SmallVec<[Ty<'tcx>; 4]> {
-    // Droppiness does not depend on regions, so let us erase them.
-    let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
-
-    let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty));
-    debug!(?ty, "components");
-    let mut out_tys = smallvec![];
-    for ty in tys {
-        if let Some(tys) = true_significant_drop_ty(tcx, ty) {
-            // Some types can be further opened up because the drop is simply delegated
-            for ty in tys {
-                if ty_seen.insert(ty) {
-                    out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen));
-                }
-            }
-        } else {
-            if ty_seen.insert(ty) {
-                out_tys.push(ty);
-            }
-        }
-    }
-    out_tys
-}
-
-#[instrument(level = "debug", skip(tcx, typing_env))]
-fn extract_component_with_significant_dtor<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    typing_env: ty::TypingEnv<'tcx>,
-    ty: Ty<'tcx>,
-) -> SmallVec<[Ty<'tcx>; 4]> {
-    let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default());
-    let mut deduplicate = FxHashSet::default();
-    tys.retain(|oty| deduplicate.insert(*oty));
-    tys.into_iter().collect()
-}
-
-/// Extract the span of the custom destructor of a type
-/// especially the span of the `impl Drop` header or its entire block
-/// when we are working with current local crate.
-#[instrument(level = "debug", skip(tcx))]
-fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Span> {
-    match ty.kind() {
-        ty::Bool
-        | ty::Char
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::Float(_)
-        | ty::Error(_)
-        | ty::Str
-        | ty::Never
-        | ty::RawPtr(_, _)
-        | ty::Ref(_, _, _)
-        | ty::FnPtr(_, _)
-        | ty::Tuple(_)
-        | ty::Dynamic(_, _, _)
-        | ty::Alias(_, _)
-        | ty::Bound(_, _)
-        | ty::Pat(_, _)
-        | ty::Placeholder(_)
-        | ty::Infer(_)
-        | ty::Slice(_)
-        | ty::Array(_, _)
-        | ty::UnsafeBinder(_) => None,
-
-        ty::Adt(adt_def, _) => {
-            let did = adt_def.did();
-            let try_local_did_span = |did: DefId| {
-                if let Some(local) = did.as_local() {
-                    tcx.source_span(local)
-                } else {
-                    tcx.def_span(did)
-                }
-            };
-            let dtor = if let Some(dtor) = tcx.adt_destructor(did) {
-                dtor.did
-            } else if let Some(dtor) = tcx.adt_async_destructor(did) {
-                dtor.future
-            } else {
-                return Some(try_local_did_span(did));
-            };
-            let def_key = tcx.def_key(dtor);
-            let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) };
-            let parent_did = DefId { index: parent_index, krate: dtor.krate };
-            Some(try_local_did_span(parent_did))
-        }
-        ty::Coroutine(did, _)
-        | ty::CoroutineWitness(did, _)
-        | ty::CoroutineClosure(did, _)
-        | ty::Closure(did, _)
-        | ty::FnDef(did, _)
-        | ty::Foreign(did) => Some(tcx.def_span(did)),
-        ty::Param(_) => None,
-    }
-}
-
 /// Check if a moved place at `idx` is a part of a BID.
 /// The use of this check is that we will consider drops on these
 /// as a drop of the overall BID and, thus, we can exclude it from the diagnosis.
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr
index 158d18f6882..601b0a38412 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.stderr
+++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr
@@ -242,6 +242,15 @@ LL |     _ = (if let Ok(_) = e.ok(4).as_ref() {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:127:5
    |
@@ -267,6 +276,15 @@ LL |     _ = (if let Ok(_) = e.err(4).as_ref() {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:145:44
    |
@@ -291,6 +309,15 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:247:43
    |
@@ -315,6 +342,15 @@ LL |         if let true = e.err(9).is_ok() {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:352:41
    |
@@ -339,6 +375,15 @@ LL |         if let Ok(_v) = e.err(8) {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:355:35
    |
@@ -363,6 +408,15 @@ LL |         if let Ok(_) = e.err(7) {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:358:34
    |
@@ -387,6 +441,15 @@ LL |         if let Ok(_) = e.err(6).as_ref() {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:361:43
    |
@@ -411,6 +474,15 @@ LL |         if let Ok(_v) = e.err(5) {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:365:35
    |
@@ -435,6 +507,15 @@ LL |         if let Ok(_) = e.err(4) {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:368:34
    |
@@ -459,6 +540,15 @@ LL |         if let Ok(_) = e.err(4).as_ref() {} else {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/drop-order-comparisons.rs:571:1
+   |
+LL | / impl<'b> Drop for LogDrop<'b> {
+LL | |     fn drop(&mut self) {
+LL | |         self.0.mark(self.1);
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/drop-order-comparisons.rs:404:43
    |
diff --git a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
index 546a5fe0fd0..070ba1c6a4c 100644
--- a/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-gated.edition2021.stderr
@@ -8,6 +8,15 @@ LL |     if let Some(_value) = Droppy.get() {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope-gated.rs:14:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope-gated.rs:30:5
    |
diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
index 029d5c74929..f1ca0ba57de 100644
--- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
+++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr
@@ -15,6 +15,15 @@ LL | |     };
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope-with-macro.rs:22:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope-with-macro.rs:12:38
    |
diff --git a/tests/ui/drop/lint-if-let-rescope.stderr b/tests/ui/drop/lint-if-let-rescope.stderr
index b17239976cc..e95ec8fcea7 100644
--- a/tests/ui/drop/lint-if-let-rescope.stderr
+++ b/tests/ui/drop/lint-if-let-rescope.stderr
@@ -8,6 +8,15 @@ LL |     if let Some(_value) = droppy().get() {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:32:5
    |
@@ -43,6 +52,24 @@ LL |     } else if let Some(_value) = droppy().get() {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:42:5
    |
@@ -75,6 +102,15 @@ LL |     } else if let Some(_value) = droppy().get() {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:54:5
    |
@@ -101,6 +137,15 @@ LL |     if let Some(1) = { if let Some(_value) = Droppy.get() { Some(1) } else
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:58:69
    |
@@ -122,6 +167,15 @@ LL |     if (if let Some(_value) = droppy().get() { true } else { false }) {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:72:53
    |
@@ -143,6 +197,15 @@ LL |     } else if (((if let Some(_value) = droppy().get() { true } else { false
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:78:62
    |
@@ -164,6 +227,15 @@ LL |     while (if let Some(_value) = droppy().get() { false } else { true }) {
    |
    = warning: this changes meaning in Rust 2024
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html>
+note: value invokes this custom destructor
+  --> $DIR/lint-if-let-rescope.rs:11:1
+   |
+LL | / impl Drop for Droppy {
+LL | |     fn drop(&mut self) {
+LL | |         println!("dropped");
+LL | |     }
+LL | | }
+   | |_^
 help: the value is now dropped here in Edition 2024
   --> $DIR/lint-if-let-rescope.rs:90:57
    |