Skip to main content

rustc_hir_analysis/collect/
dump.rs

1use 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::ty::{self, TyCtxt, TypeVisitableExt, Unnormalized};
7use rustc_span::sym;
8
9pub(crate) fn generics(tcx: TyCtxt<'_>) {
10    for did in tcx.hir_crate_items(()).definitions() {
11        if did == hir::def_id::CRATE_DEF_ID {
12            continue;
13        }
14
15        if {
        {
            'done:
                {
                for i in ::rustc_hir::attrs::HasAttrs::get_attrs(did, &tcx) {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(RustcDumpGenerics) => {
                            break 'done Some(());
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(tcx, did, RustcDumpGenerics) {
16            let span = tcx.def_span(did);
17
18            let mut diag =
19                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));
20
21            let generics = tcx.generics_of(did);
22            diag.span_note(tcx.def_span(did), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:#?}", generics))
    })format!("{generics:#?}"));
23            diag.emit();
24        }
25    }
26}
27
28pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) {
29    if !{
        'done:
            {
            for i in tcx.hir_krate_attrs() {
                #[allow(unused_imports)]
                use rustc_hir::attrs::AttributeKind::*;
                let i: &rustc_hir::Attribute = i;
                match i {
                    rustc_hir::Attribute::Parsed(RustcDumpHiddenTypeOfOpaques)
                        => {
                        break 'done Some(());
                    }
                    rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }.is_some()find_attr!(tcx, crate, RustcDumpHiddenTypeOfOpaques) {
30        return;
31    }
32    for id in tcx.hir_crate_items(()).opaques() {
33        if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
34        | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
35            tcx.hir_expect_opaque_ty(id).origin
36            && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
37            && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
38        {
39            continue;
40        }
41
42        let ty = tcx.type_of(id).instantiate_identity().skip_norm_wip();
43        let span = tcx.def_span(id);
44        tcx.dcx().emit_err(crate::diagnostics::TypeOf { span, ty });
45    }
46}
47
48pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
49    for id in tcx.hir_crate_items(()).owners() {
50        #[expect(deprecated)] // we don't want to unnecessarily retrieve the attrs twice in a row.
51        let attrs = tcx.get_all_attrs(id);
52
53        if {
    {
            'done:
                {
                for i in attrs {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(RustcDumpPredicates) => {
                            break 'done Some(());
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(attrs, RustcDumpPredicates) {
54            let preds = tcx
55                .predicates_of(id)
56                .instantiate_identity(tcx)
57                .predicates
58                .into_iter()
59                .map(Unnormalized::skip_norm_wip);
60            let span = tcx.def_span(id);
61
62            let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str());
63            for pred in preds {
64                diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", pred))
    })format!("{pred:?}"));
65            }
66            diag.emit();
67        }
68
69        if {
    {
            'done:
                {
                for i in attrs {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(RustcDumpItemBounds) => {
                            break 'done Some(());
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(attrs, RustcDumpItemBounds) {
70            let name = sym::rustc_dump_item_bounds.as_str();
71
72            match tcx.def_kind(id) {
73                DefKind::AssocTy => {
74                    let bounds = tcx.item_bounds(id).instantiate_identity().skip_norm_wip();
75                    let span = tcx.def_span(id);
76
77                    let mut diag = tcx.dcx().struct_span_err(span, name);
78                    for bound in bounds {
79                        diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", bound))
    })format!("{bound:?}"));
80                    }
81                    diag.emit()
82                }
83                kind => tcx.dcx().span_delayed_bug(
84                    tcx.def_span(id),
85                    ::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:?}"),
86                ),
87            };
88        }
89    }
90}
91
92pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
93    for iid in tcx.hir_free_items() {
94        let did = iid.owner_id.def_id;
95        if {
        {
            'done:
                {
                for i in ::rustc_hir::attrs::HasAttrs::get_attrs(did, &tcx) {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(RustcDumpDefParents) => {
                            break 'done Some(());
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(tcx, did, RustcDumpDefParents) {
96            struct AnonConstFinder<'tcx> {
97                tcx: TyCtxt<'tcx>,
98                anon_consts: Vec<LocalDefId>,
99            }
100
101            impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
102                type NestedFilter = nested_filter::All;
103
104                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
105                    self.tcx
106                }
107
108                fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
109                    self.anon_consts.push(c.def_id);
110                    intravisit::walk_anon_const(self, c)
111                }
112            }
113
114            // Look for any anon consts inside of this item as there is no way to apply
115            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
116            // to see what its def parent is.
117            let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: ::alloc::vec::Vec::new()vec![] };
118            intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
119
120            for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
121                let span = tcx.def_span(did);
122
123                let mut diag = tcx
124                    .dcx()
125                    .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));
126
127                let mut current_did = did.to_def_id();
128                while let Some(parent_did) = tcx.opt_parent(current_did) {
129                    current_did = parent_did;
130                    diag.span_note(tcx.def_span(parent_did), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", parent_did))
    })format!("{parent_did:?}"));
131                }
132                diag.emit();
133            }
134        }
135    }
136}
137
138pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
139    for id in tcx.hir_free_items() {
140        let def_id = id.owner_id.def_id;
141
142        let Some(&attr_span) = {
    {
        'done:
            {
            for i in ::rustc_hir::attrs::HasAttrs::get_attrs(def_id, &tcx) {
                #[allow(unused_imports)]
                use rustc_hir::attrs::AttributeKind::*;
                let i: &rustc_hir::Attribute = i;
                match i {
                    rustc_hir::Attribute::Parsed(RustcDumpVtable(span)) => {
                        break 'done Some(span);
                    }
                    rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, def_id, RustcDumpVtable(span) => span) else {
143            continue;
144        };
145
146        let vtable_entries = match tcx.hir_item(id).kind {
147            hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
148                let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
149                if trait_ref.skip_normalization().has_non_region_param() {
150                    tcx.dcx().span_err(
151                        attr_span,
152                        "`rustc_dump_vtable` must be applied to non-generic impl",
153                    );
154                    continue;
155                }
156                if !tcx.is_dyn_compatible(trait_ref.skip_normalization().def_id) {
157                    tcx.dcx().span_err(
158                        attr_span,
159                        "`rustc_dump_vtable` must be applied to dyn-compatible trait",
160                    );
161                    continue;
162                }
163                let Ok(trait_ref) = tcx
164                    .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
165                else {
166                    tcx.dcx().span_err(
167                        attr_span,
168                        "`rustc_dump_vtable` applied to impl header that cannot be normalized",
169                    );
170                    continue;
171                };
172                tcx.vtable_entries(trait_ref)
173            }
174            hir::ItemKind::TyAlias(..) => {
175                let ty = tcx.type_of(def_id).instantiate_identity();
176                if ty.has_non_region_param() {
177                    tcx.dcx().span_err(
178                        attr_span,
179                        "`rustc_dump_vtable` must be applied to non-generic type",
180                    );
181                    continue;
182                }
183                let Ok(ty) =
184                    tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
185                else {
186                    tcx.dcx().span_err(
187                        attr_span,
188                        "`rustc_dump_vtable` applied to type alias that cannot be normalized",
189                    );
190                    continue;
191                };
192                let ty::Dynamic(data, _) = *ty.kind() else {
193                    tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type");
194                    continue;
195                };
196                if let Some(principal) = data.principal() {
197                    tcx.vtable_entries(
198                        tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
199                    )
200                } else {
201                    TyCtxt::COMMON_VTABLE_ENTRIES
202                }
203            }
204            _ => {
205                tcx.dcx().span_err(
206                    attr_span,
207                    "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
208                );
209                continue;
210            }
211        };
212
213        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:#?}"));
214    }
215}