Skip to main content

rustc_hir_analysis/collect/
dump.rs

1use 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            // Look for any anon consts inside of this item as there is no way to apply
78            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
79            // to see what its def parent is.
80            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}