diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a4245f0908e33..910402d5499fd 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 85e1c600d6da4..c73d3a5390d93 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, + } + + 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 cf41f51f74814..44f1830a3b17b 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 8b7a63f5eb9b6..7da9211bcbf74 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 0000000000000..af1c210d2cd18 --- /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() {} + +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 0000000000000..b2cc32d09b07e --- /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 +