Skip to main content

rustc_hir_analysis/collect/
dump.rs

1use rustc_hir as hir;
2use rustc_hir::def_id::LocalDefId;
3use rustc_hir::{find_attr, 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 !{
        '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(RustcHiddenTypeOfOpaques) => {
                        break 'done Some(());
                    }
                    rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }.is_some()find_attr!(tcx, crate, RustcHiddenTypeOfOpaques) {
10        return;
11    }
12    for id in tcx.hir_crate_items(()).opaques() {
13        if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }
14        | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } =
15            tcx.hir_expect_opaque_ty(id).origin
16            && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)
17            && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()
18        {
19            continue;
20        }
21
22        let ty = tcx.type_of(id).instantiate_identity();
23        let span = tcx.def_span(id);
24        tcx.dcx().emit_err(crate::errors::TypeOf { span, ty });
25    }
26}
27
28pub(crate) fn predicates_and_item_bounds(tcx: TyCtxt<'_>) {
29    for id in tcx.hir_crate_items(()).owners() {
30        if {

        #[allow(deprecated)]
        {
            {
                'done:
                    {
                    for i in tcx.get_all_attrs(id) {
                        #[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!(tcx, id, RustcDumpPredicates) {
31            let preds = tcx.predicates_of(id).instantiate_identity(tcx).predicates;
32            let span = tcx.def_span(id);
33
34            let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_predicates.as_str());
35            for pred in preds {
36                diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", pred))
    })format!("{pred:?}"));
37            }
38            diag.emit();
39        }
40        if {

        #[allow(deprecated)]
        {
            {
                'done:
                    {
                    for i in tcx.get_all_attrs(id) {
                        #[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!(tcx, id, RustcDumpItemBounds) {
41            let bounds = tcx.item_bounds(id).instantiate_identity();
42            let span = tcx.def_span(id);
43
44            let mut diag = tcx.dcx().struct_span_err(span, sym::rustc_dump_item_bounds.as_str());
45            for bound in bounds {
46                diag.note(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", bound))
    })format!("{bound:?}"));
47            }
48            diag.emit();
49        }
50    }
51}
52
53pub(crate) fn def_parents(tcx: TyCtxt<'_>) {
54    for iid in tcx.hir_free_items() {
55        let did = iid.owner_id.def_id;
56        if {

        #[allow(deprecated)]
        {
            {
                'done:
                    {
                    for i in tcx.get_all_attrs(did) {
                        #[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) {
57            struct AnonConstFinder<'tcx> {
58                tcx: TyCtxt<'tcx>,
59                anon_consts: Vec<LocalDefId>,
60            }
61
62            impl<'tcx> intravisit::Visitor<'tcx> for AnonConstFinder<'tcx> {
63                type NestedFilter = nested_filter::All;
64
65                fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
66                    self.tcx
67                }
68
69                fn visit_anon_const(&mut self, c: &'tcx rustc_hir::AnonConst) {
70                    self.anon_consts.push(c.def_id);
71                    intravisit::walk_anon_const(self, c)
72                }
73            }
74
75            // Look for any anon consts inside of this item as there is no way to apply
76            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
77            // to see what its def parent is.
78            let mut anon_ct_finder = AnonConstFinder { tcx, anon_consts: ::alloc::vec::Vec::new()vec![] };
79            intravisit::walk_item(&mut anon_ct_finder, tcx.hir_item(iid));
80
81            for did in [did].into_iter().chain(anon_ct_finder.anon_consts) {
82                let span = tcx.def_span(did);
83
84                let mut diag = tcx.dcx().struct_span_err(
85                    span,
86                    ::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()),
87                );
88
89                let mut current_did = did.to_def_id();
90                while let Some(parent_did) = tcx.opt_parent(current_did) {
91                    current_did = parent_did;
92                    diag.span_note(tcx.def_span(parent_did), ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", parent_did))
    })format!("{parent_did:?}"));
93                }
94                diag.emit();
95            }
96        }
97    }
98}
99
100pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
101    for id in tcx.hir_free_items() {
102        let def_id = id.owner_id.def_id;
103
104        let Some(&attr_span) = {

    #[allow(deprecated)]
    {
        {
            'done:
                {
                for i in tcx.get_all_attrs(def_id) {
                    #[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 {
105            continue;
106        };
107
108        let vtable_entries = match tcx.hir_item(id).kind {
109            hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
110                let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
111                if trait_ref.has_non_region_param() {
112                    tcx.dcx().span_err(
113                        attr_span,
114                        "`rustc_dump_vtable` must be applied to non-generic impl",
115                    );
116                    continue;
117                }
118                if !tcx.is_dyn_compatible(trait_ref.def_id) {
119                    tcx.dcx().span_err(
120                        attr_span,
121                        "`rustc_dump_vtable` must be applied to dyn-compatible trait",
122                    );
123                    continue;
124                }
125                let Ok(trait_ref) = tcx
126                    .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
127                else {
128                    tcx.dcx().span_err(
129                        attr_span,
130                        "`rustc_dump_vtable` applied to impl header that cannot be normalized",
131                    );
132                    continue;
133                };
134                tcx.vtable_entries(trait_ref)
135            }
136            hir::ItemKind::TyAlias(..) => {
137                let ty = tcx.type_of(def_id).instantiate_identity();
138                if ty.has_non_region_param() {
139                    tcx.dcx().span_err(
140                        attr_span,
141                        "`rustc_dump_vtable` must be applied to non-generic type",
142                    );
143                    continue;
144                }
145                let Ok(ty) =
146                    tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
147                else {
148                    tcx.dcx().span_err(
149                        attr_span,
150                        "`rustc_dump_vtable` applied to type alias that cannot be normalized",
151                    );
152                    continue;
153                };
154                let ty::Dynamic(data, _) = *ty.kind() else {
155                    tcx.dcx().span_err(attr_span, "`rustc_dump_vtable` to type alias of dyn type");
156                    continue;
157                };
158                if let Some(principal) = data.principal() {
159                    tcx.vtable_entries(
160                        tcx.instantiate_bound_regions_with_erased(principal).with_self_ty(tcx, ty),
161                    )
162                } else {
163                    TyCtxt::COMMON_VTABLE_ENTRIES
164                }
165            }
166            _ => {
167                tcx.dcx().span_err(
168                    attr_span,
169                    "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
170                );
171                continue;
172            }
173        };
174
175        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:#?}"));
176    }
177}