Skip to main content

rustc_hir_analysis/collect/
dump.rs

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