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