diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index a4245f0908e..910402d5499 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1117,6 +1117,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         TEST, rustc_dump_predicates, Normal, template!(Word),
         WarnFollowing, EncodeCrossCrate::No
     ),
+    rustc_attr!(
+        TEST, rustc_dump_def_parents, Normal, template!(Word),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
     rustc_attr!(
         TEST, rustc_object_lifetime_default, Normal, template!(Word),
         WarnFollowing, EncodeCrossCrate::No
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 85e1c600d6d..c73d3a5390d 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -1,5 +1,7 @@
 use rustc_hir::def::DefKind;
-use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::intravisit;
+use rustc_middle::hir::nested_filter::OnlyBodies;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::sym;
 
@@ -41,3 +43,49 @@ pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
         }
     }
 }
+
+pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
+    for did in tcx.hir().body_owners() {
+        if tcx.has_attr(did, sym::rustc_dump_def_parents) {
+            struct AnonConstFinder<'tcx> {
+                tcx: TyCtxt<'tcx>,
+                anon_consts: Vec<LocalDefId>,
+            }
+
+            impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
+                type NestedFilter = OnlyBodies;
+
+                fn nested_visit_map(&mut self) -> Self::Map {
+                    self.tcx.hir()
+                }
+
+                fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
+                    self.anon_consts.push(c.def_id);
+                    intravisit::walk_anon_const(self, c)
+                }
+            }
+
+            // Look for any anon consts inside of this body owner as there is no way to apply
+            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
+            // to see what its def parent is.
+            let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: vec![] };
+            intravisit::walk_expr(&mut anon_ct_finder, tcx.hir().body_owned_by(did).value);
+
+            for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
+                let span = tcx.def_span(did);
+
+                let mut diag = tcx.dcx().struct_span_err(
+                    span,
+                    format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()),
+                );
+
+                let mut current_did = did.to_def_id();
+                while let Some(parent_did) = tcx.opt_parent(current_did) {
+                    current_did = parent_did;
+                    diag.span_note(tcx.def_span(parent_did), format!("{parent_did:?}"));
+                }
+                diag.emit();
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index cf41f51f748..44f1830a3b1 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -175,6 +175,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         tcx.sess.time("variance_dumping", || variance::dump::variances(tcx));
         collect::dump::opaque_hidden_types(tcx);
         collect::dump::predicates_and_item_bounds(tcx);
+        collect::dump::def_parents(tcx);
     }
 
     // Make sure we evaluate all static and (non-associated) const items, even if unused.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 8b7a63f5eb9..7da9211bcbf 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1614,6 +1614,7 @@ symbols! {
         rustc_do_not_const_check,
         rustc_doc_primitive,
         rustc_dummy,
+        rustc_dump_def_parents,
         rustc_dump_item_bounds,
         rustc_dump_predicates,
         rustc_dump_user_args,
diff --git a/tests/ui/attributes/dump_def_parents.rs b/tests/ui/attributes/dump_def_parents.rs
new file mode 100644
index 00000000000..af1c210d2cd
--- /dev/null
+++ b/tests/ui/attributes/dump_def_parents.rs
@@ -0,0 +1,34 @@
+//@ normalize-stderr-test "DefId\(.+?\)" -> "DefId(..)"
+#![feature(rustc_attrs)]
+
+fn bar() {
+    fn foo() {
+        fn baz() {
+            #[rustc_dump_def_parents]
+            || {
+                //~^ ERROR: rustc_dump_def_parents: DefId
+                qux::<
+                    {
+                        //~^ ERROR: rustc_dump_def_parents: DefId
+                        fn inhibits_dump() {
+                            qux::<
+                                {
+                                    "hi";
+                                    1
+                                },
+                            >();
+                        }
+
+                        qux::<{ 1 + 1 }>();
+                        //~^ ERROR: rustc_dump_def_parents: DefId
+                        1
+                    },
+                >();
+            };
+        }
+    }
+}
+
+const fn qux<const N: usize>() {}
+
+fn main() {}
diff --git a/tests/ui/attributes/dump_def_parents.stderr b/tests/ui/attributes/dump_def_parents.stderr
new file mode 100644
index 00000000000..b2cc32d09b0
--- /dev/null
+++ b/tests/ui/attributes/dump_def_parents.stderr
@@ -0,0 +1,128 @@
+error: rustc_dump_def_parents: DefId(..)
+  --> $DIR/dump_def_parents.rs:8:13
+   |
+LL |             || {
+   |             ^^
+   |
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:6:9
+   |
+LL |         fn baz() {
+   |         ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:5:5
+   |
+LL |     fn foo() {
+   |     ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:4:1
+   |
+LL | fn bar() {
+   | ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:2:1
+   |
+LL | / #![feature(rustc_attrs)]
+LL | |
+LL | | fn bar() {
+LL | |     fn foo() {
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: rustc_dump_def_parents: DefId(..)
+  --> $DIR/dump_def_parents.rs:11:21
+   |
+LL | /                     {
+LL | |
+LL | |                         fn inhibits_dump() {
+LL | |                             qux::<
+...  |
+LL | |                         1
+LL | |                     },
+   | |_____________________^
+   |
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:8:13
+   |
+LL |             || {
+   |             ^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:6:9
+   |
+LL |         fn baz() {
+   |         ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:5:5
+   |
+LL |     fn foo() {
+   |     ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:4:1
+   |
+LL | fn bar() {
+   | ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:2:1
+   |
+LL | / #![feature(rustc_attrs)]
+LL | |
+LL | | fn bar() {
+LL | |     fn foo() {
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: rustc_dump_def_parents: DefId(..)
+  --> $DIR/dump_def_parents.rs:22:31
+   |
+LL |                         qux::<{ 1 + 1 }>();
+   |                               ^^^^^^^^^
+   |
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:11:21
+   |
+LL | /                     {
+LL | |
+LL | |                         fn inhibits_dump() {
+LL | |                             qux::<
+...  |
+LL | |                         1
+LL | |                     },
+   | |_____________________^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:8:13
+   |
+LL |             || {
+   |             ^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:6:9
+   |
+LL |         fn baz() {
+   |         ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:5:5
+   |
+LL |     fn foo() {
+   |     ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:4:1
+   |
+LL | fn bar() {
+   | ^^^^^^^^
+note: DefId(..)
+  --> $DIR/dump_def_parents.rs:2:1
+   |
+LL | / #![feature(rustc_attrs)]
+LL | |
+LL | | fn bar() {
+LL | |     fn foo() {
+...  |
+LL | |
+LL | | fn main() {}
+   | |____________^
+
+error: aborting due to 3 previous errors
+