rustc_hir_analysis/collect/
dump.rs1use rustc_hir as hir;
2use rustc_hir::attrs::AttributeKind;
3use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
4use rustc_hir::{find_attr, intravisit};
5use rustc_middle::hir::nested_filter;
6use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
7use rustc_span::sym;
8
9pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
10 if !tcx.has_attr(CRATE_DEF_ID, sym::rustc_hidden_type_of_opaques) {
11 return;
12 }
13
14 for id in tcx.hir_crate_items(()).opaques() {
15 if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
16 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
17 tcx.hir_expect_opaque_ty(id).origin
18 && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
19 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
20 {
21 continue;
22 }
23
24 let ty = tcx.type_of(id).instantiate_identity();
25 let span = tcx.def_span(id);
26 tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
27 }
28}
29
30pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
31 for id in tcx.hir_crate_items(()).owners() {
32 if {
{
'done:
{
for i in tcx.get_all_attrs(id) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcDumpPredicates)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpPredicates) {
33 let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates;
34 let span = tcx.def_span(id);
35
36 let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str());
37 for pred in preds {
38 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", pred))
})format!("{pred:?}"));
39 }
40 diag.emit();
41 }
42 if {
{
'done:
{
for i in tcx.get_all_attrs(id) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcDumpItemBounds)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(tcx.get_all_attrs(id), AttributeKind::RustcDumpItemBounds) {
43 let bounds = tcx.item_bounds(id).instantiate_identity();
44 let span = tcx.def_span(id);
45
46 let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str());
47 for bound in bounds {
48 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", bound))
})format!("{bound:?}"));
49 }
50 diag.emit();
51 }
52 }
53}
54
55pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
56 for iid in tcx.hir_free_items() {
57 let did = iid.owner_id.def_id;
58 if {
{
'done:
{
for i in tcx.get_all_attrs(did) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcDumpDefParents)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(tcx.get_all_attrs(did), AttributeKind::RustcDumpDefParents) {
59 struct AnonConstFinder<'tcx> {
60 tcx: TyCtxt<'tcx>,
61 anon_consts: Vec<LocalDefId>,
62 }
63
64 impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
65 type NestedFilter = nested_filter::All;
66
67 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
68 self.tcx
69 }
70
71 fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
72 self.anon_consts.push(c.def_id);
73 intravisit::walk_anon_const(self, c)
74 }
75 }
76
77 let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: ::alloc::vec::Vec::new()vec![] };
81 intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
82
83 for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
84 let span = tcx.def_span(did);
85
86 let mut diag = tcx.dcx().struct_span_err(
87 span,
88 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: {1:?}",
sym::rustc_dump_def_parents.as_str(), did))
})format!("{}: {did:?}", sym::rustc_dump_def_parents.as_str()),
89 );
90
91 let mut current_did = did.to_def_id();
92 while let Some(parent_did) = tcx.opt_parent(current_did) {
93 current_did = parent_did;
94 diag.span_note(tcx.def_span(parent_did), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", parent_did))
})format!("{parent_did:?}"));
95 }
96 diag.emit();
97 }
98 }
99 }
100}
101
102pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
103 for id in tcx.hir_free_items() {
104 let def_id = id.owner_id.def_id;
105
106 let Some(&attr_span) =
107 {
'done:
{
for i in tcx.get_all_attrs(def_id) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcDumpVtable(span))
=> {
break 'done Some(span);
}
_ => {}
}
}
None
}
}find_attr!(tcx.get_all_attrs(def_id), AttributeKind::RustcDumpVtable(span) => span)
108 else {
109 continue;
110 };
111
112 let vtable_entries = match tcx.hir_item(id).kind {
113 hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
114 let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
115 if trait_ref.has_non_region_param() {
116 tcx.dcx().span_err(
117 attr_span,
118 "`rustc_dump_vtable` must be applied to non-generic impl",
119 );
120 continue;
121 }
122 if !tcx.is_dyn_compatible(trait_ref.def_id) {
123 tcx.dcx().span_err(
124 attr_span,
125 "`rustc_dump_vtable` must be applied to dyn-compatible trait",
126 );
127 continue;
128 }
129 let Ok(trait_ref) = tcx
130 .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
131 else {
132 tcx.dcx().span_err(
133 attr_span,
134 "`rustc_dump_vtable` applied to impl header that cannot be normalized",
135 );
136 continue;
137 };
138 tcx.vtable_entries(trait_ref)
139 }
140 hir::ItemKind::TyAlias(..) => {
141 let ty = tcx.type_of(def_id).instantiate_identity();
142 if ty.has_non_region_param() {
143 tcx.dcx().span_err(
144 attr_span,
145 "`rustc_dump_vtable` must be applied to non-generic type",
146 );
147 continue;
148 }
149 let Ok(ty) =
150 tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
151 else {
152 tcx.dcx().span_err(
153 attr_span,
154 "`rustc_dump_vtable` applied to type alias that cannot be normalized",
155 );
156 continue;
157 };
158 let ty::Dynamic(data, _) = *ty.kind() else {
159 tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type");
160 continue;
161 };
162 if let Some(principal) = data.principal() {
163 tcx.vtable_entries(
164 tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
165 )
166 } else {
167 TyCtxt::COMMON_VTABLE_ENTRIES
168 }
169 }
170 _ => {
171 tcx.dcx().span_err(
172 attr_span,
173 "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
174 );
175 continue;
176 }
177 };
178
179 tcx.dcx().span_err(tcx.def_span(def_id), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("vtable entries: {0:#?}",
vtable_entries))
})format!("vtable entries: {vtable_entries:#?}"));
180 }
181}