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::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)] // we don't want to unnecessarily retrieve the attrs twice in a row.
76        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            // Look for any anon consts inside of this item as there is no way to apply
140            // the `rustc_dump_def_parents` attribute to the anon const so it would not be possible
141            // to see what its def parent is.
142            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}