rustc_hir_analysis/collect/
dump.rs1use rustc_hir as hir;
2use rustc_hir::def::DefKind;
3use rustc_hir::def_id::LocalDefId;
4use rustc_hir::{find_attr, intravisit};
5use rustc_middle::hir::nested_filter;
6use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
7use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, Unnormalized};
8use rustc_span::sym;
9
10pub(crate) fn generics(tcx: TyCtxt<'_>) {
11 for did in tcx.hir_crate_items(()).definitions() {
12 if did == hir::def_id::CRATE_DEF_ID {
13 continue;
14 }
15
16 if {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(did, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpGenerics) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(tcx, did, RustcDumpGenerics) {
17 let span = tcx.def_span(did);
18
19 let mut diag =
20 tcx.dcx().struct_span_err(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: {1:?}",
sym::rustc_dump_generics, did))
})format!("{}: {did:?}", sym::rustc_dump_generics));
21
22 let generics = tcx.generics_of(did);
23 diag.span_note(tcx.def_span(did), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:#?}", generics))
})format!("{generics:#?}"));
24 diag.emit();
25 }
26 }
27}
28
29pub(crate) fn object_lifetime_defaults(tcx: TyCtxt<'_>) {
30 for def_id in tcx.hir_crate_items(()).definitions() {
31 if def_id == hir::def_id::CRATE_DEF_ID {
32 continue;
33 }
34
35 if !{
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpObjectLifetimeDefaults)
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(tcx, def_id, RustcDumpObjectLifetimeDefaults) {
36 continue;
37 }
38
39 for param in &tcx.generics_of(def_id).own_params {
40 let ty::GenericParamDefKind::Type { .. } = param.kind else { continue };
41 let default = tcx.object_lifetime_default(param.def_id);
42 let repr = match default {
43 ObjectLifetimeDefault::Empty => "Empty".to_owned(),
44 ObjectLifetimeDefault::Static => "'static".to_owned(),
45 ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
46 ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
47 };
48 tcx.dcx().span_err(tcx.def_span(param.def_id), repr);
49 }
50 }
51}
52
53pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
54 if !{
'done:
{
for i in tcx.hir_krate_attrs() {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpHiddenTypeOfOpaques)
=> {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()find_attr!(tcx, crate, RustcDumpHiddenTypeOfOpaques) {
55 return;
56 }
57 for id in tcx.hir_crate_items(()).opaques() {
58 if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
59 | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
60 tcx.hir_expect_opaque_ty(id).origin
61 && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
62 && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
63 {
64 continue;
65 }
66
67 let ty = tcx.type_of(id).instantiate_identity().skip_norm_wip();
68 let span = tcx.def_span(id);
69 tcx.dcx().emit_err(crate::diagnostics::TypeOf { span, ty });
70 }
71}
72
73pub(crate) fn clauses_and_item_bounds(tcx: TyCtxt<'_>) {
74 for id in tcx.hir_crate_items(()).owners() {
75 #[expect(deprecated)] let attrs = tcx.get_all_attrs(id);
77
78 if {
{
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpClauses) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(attrs, RustcDumpClauses) {
79 let clauses = tcx
80 .clauses_of(id)
81 .instantiate_identity(tcx)
82 .clauses
83 .into_iter()
84 .map(Unnormalized::skip_norm_wip);
85 let span = tcx.def_span(id);
86
87 let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_clauses.as_str());
88 for clause in clauses {
89 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", clause))
})format!("{clause:?}"));
90 }
91 diag.emit();
92 }
93
94 if {
{
'done:
{
for i in attrs {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpItemBounds) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}.is_some()
}find_attr!(attrs, RustcDumpItemBounds) {
95 let name = sym::rustc_dump_item_bounds.as_str();
96
97 match tcx.def_kind(id) {
98 DefKind::AssocTy => {
99 let bounds = tcx.item_bounds(id).instantiate_identity().skip_norm_wip();
100 let span = tcx.def_span(id);
101
102 let mut diag = tcx.dcx().struct_span_err(span, name);
103 for bound in bounds {
104 diag.note(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", bound))
})format!("{bound:?}"));
105 }
106 diag.emit()
107 }
108 kind => tcx.dcx().span_delayed_bug(
109 tcx.def_span(id),
110 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("attr parsing didn\'t report an error for `#[{0}]` on {1:?}",
name, kind))
})format!("attr parsing didn't report an error for `#[{name}]` on {kind:?}"),
111 ),
112 };
113 }
114 }
115}
116
117pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
118 for iid in tcx.hir_free_items() {
119 let did = iid.owner_id.def_id;
120 if {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(did, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpDefParents) => {
break 'done Some(());
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}.is_some()find_attr!(tcx, did, RustcDumpDefParents) {
121 struct AnonConstFinder<'tcx> {
122 tcx: TyCtxt<'tcx>,
123 anon_consts: Vec<LocalDefId>,
124 }
125
126 impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
127 type NestedFilter = nested_filter::All;
128
129 fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
130 self.tcx
131 }
132
133 fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
134 self.anon_consts.push(c.def_id);
135 intravisit::walk_anon_const(self, c)
136 }
137 }
138
139 let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: ::alloc::vec::Vec::new()vec![] };
143 intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
144
145 for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
146 let span = tcx.def_span(did);
147
148 let mut diag = tcx
149 .dcx()
150 .struct_span_err(span, ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}: {1:?}",
sym::rustc_dump_def_parents, did))
})format!("{}: {did:?}", sym::rustc_dump_def_parents));
151
152 let mut current_did = did.to_def_id();
153 while let Some(parent_did) = tcx.opt_parent(current_did) {
154 current_did = parent_did;
155 diag.span_note(tcx.def_span(parent_did), ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", parent_did))
})format!("{parent_did:?}"));
156 }
157 diag.emit();
158 }
159 }
160 }
161}
162
163pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
164 for id in tcx.hir_free_items() {
165 let def_id = id.owner_id.def_id;
166
167 let Some(&attr_span) = {
{
'done:
{
for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &tcx) {
#[allow(unused_imports)]
use ::rustc_attr_ir::AttributeKind::*;
let i: &::rustc_attr_ir::Attribute = i;
match i {
::rustc_attr_ir::Attribute::Parsed(RustcDumpVtable(span)) =>
{
break 'done Some(span);
}
::rustc_attr_ir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}find_attr!(tcx, def_id, RustcDumpVtable(span) => span) else {
168 continue;
169 };
170
171 let vtable_entries = match tcx.hir_item(id).kind {
172 hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
173 let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
174 if trait_ref.skip_normalization().has_non_region_param() {
175 tcx.dcx().span_err(
176 attr_span,
177 "`rustc_dump_vtable` must be applied to non-generic impl",
178 );
179 continue;
180 }
181 if !tcx.is_dyn_compatible(trait_ref.skip_normalization().def_id) {
182 tcx.dcx().span_err(
183 attr_span,
184 "`rustc_dump_vtable` must be applied to dyn-compatible trait",
185 );
186 continue;
187 }
188 let Ok(trait_ref) = tcx
189 .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
190 else {
191 tcx.dcx().span_err(
192 attr_span,
193 "`rustc_dump_vtable` applied to impl header that cannot be normalized",
194 );
195 continue;
196 };
197 tcx.vtable_entries(trait_ref)
198 }
199 hir::ItemKind::TyAlias(..) => {
200 let ty = tcx.type_of(def_id).instantiate_identity();
201 if ty.has_non_region_param() {
202 tcx.dcx().span_err(
203 attr_span,
204 "`rustc_dump_vtable` must be applied to non-generic type",
205 );
206 continue;
207 }
208 let Ok(ty) =
209 tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
210 else {
211 tcx.dcx().span_err(
212 attr_span,
213 "`rustc_dump_vtable` applied to type alias that cannot be normalized",
214 );
215 continue;
216 };
217 let ty::Dynamic(data, _) = *ty.kind() else {
218 tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type");
219 continue;
220 };
221 if let Some(principal) = data.principal() {
222 tcx.vtable_entries(
223 tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
224 )
225 } else {
226 TyCtxt::COMMON_VTABLE_ENTRIES
227 }
228 }
229 _ => {
230 tcx.dcx().span_err(
231 attr_span,
232 "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
233 );
234 continue;
235 }
236 };
237
238 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:#?}"));
239 }
240}