rustc_metadata/rmeta/decoder/
cstore_impl.rs

1use std::any::Any;
2use std::mem;
3use std::sync::Arc;
4
5use rustc_hir::attrs::Deprecation;
6use rustc_hir::def::{CtorKind, DefKind};
7use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
8use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
9use rustc_middle::arena::ArenaAllocatable;
10use rustc_middle::bug;
11use rustc_middle::metadata::{AmbigModChild, ModChild};
12use rustc_middle::middle::exported_symbols::ExportedSymbol;
13use rustc_middle::middle::stability::DeprecationEntry;
14use rustc_middle::query::{ExternProviders, LocalCrate};
15use rustc_middle::ty::fast_reject::SimplifiedType;
16use rustc_middle::ty::{self, TyCtxt};
17use rustc_middle::util::Providers;
18use rustc_serialize::Decoder;
19use rustc_session::StableCrateId;
20use rustc_session::cstore::{CrateStore, ExternCrate};
21use rustc_span::hygiene::ExpnId;
22use rustc_span::{Span, Symbol, kw};
23
24use super::{Decodable, DecodeIterator};
25use crate::creader::{CStore, LoadedMacro};
26use crate::rmeta::AttrFlags;
27use crate::rmeta::table::IsDefault;
28use crate::{eii, foreign_modules, native_libs};
29
30trait ProcessQueryValue<'tcx, T> {
31    fn process_decoded(self, _tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> T;
32}
33
34impl<T> ProcessQueryValue<'_, T> for T {
35    #[inline(always)]
36    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> T {
37        self
38    }
39}
40
41impl<'tcx, T> ProcessQueryValue<'tcx, ty::EarlyBinder<'tcx, T>> for T {
42    #[inline(always)]
43    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> ty::EarlyBinder<'tcx, T> {
44        ty::EarlyBinder::bind(self)
45    }
46}
47
48impl<T> ProcessQueryValue<'_, T> for Option<T> {
49    #[inline(always)]
50    fn process_decoded(self, _tcx: TyCtxt<'_>, err: impl Fn() -> !) -> T {
51        if let Some(value) = self { value } else { err() }
52    }
53}
54
55impl<'tcx, T: ArenaAllocatable<'tcx>> ProcessQueryValue<'tcx, &'tcx T> for Option<T> {
56    #[inline(always)]
57    fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx T {
58        if let Some(value) = self { tcx.arena.alloc(value) } else { err() }
59    }
60}
61
62impl<T, E> ProcessQueryValue<'_, Result<Option<T>, E>> for Option<T> {
63    #[inline(always)]
64    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Result<Option<T>, E> {
65        Ok(self)
66    }
67}
68
69impl<'tcx, D: Decoder, T: Copy + Decodable<D>> ProcessQueryValue<'tcx, &'tcx [T]>
70    for Option<DecodeIterator<T, D>>
71{
72    #[inline(always)]
73    fn process_decoded(self, tcx: TyCtxt<'tcx>, err: impl Fn() -> !) -> &'tcx [T] {
74        if let Some(iter) = self { tcx.arena.alloc_from_iter(iter) } else { err() }
75    }
76}
77
78impl<'tcx, D: Decoder, T: Copy + Decodable<D>> ProcessQueryValue<'tcx, Option<&'tcx [T]>>
79    for Option<DecodeIterator<T, D>>
80{
81    #[inline(always)]
82    fn process_decoded(self, tcx: TyCtxt<'tcx>, _err: impl Fn() -> !) -> Option<&'tcx [T]> {
83        if let Some(iter) = self { Some(&*tcx.arena.alloc_from_iter(iter)) } else { None }
84    }
85}
86
87impl ProcessQueryValue<'_, Option<DeprecationEntry>> for Option<Deprecation> {
88    #[inline(always)]
89    fn process_decoded(self, _tcx: TyCtxt<'_>, _err: impl Fn() -> !) -> Option<DeprecationEntry> {
90        self.map(DeprecationEntry::external)
91    }
92}
93
94macro_rules! provide_one {
95    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table }) => {
96        provide_one! {
97            $tcx, $def_id, $other, $cdata, $name => {
98                $cdata
99                    .root
100                    .tables
101                    .$name
102                    .get(($cdata, $tcx), $def_id.index)
103                    .map(|lazy| lazy.decode(($cdata, $tcx)))
104                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
105            }
106        }
107    };
108    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_defaulted_array }) => {
109        provide_one! {
110            $tcx, $def_id, $other, $cdata, $name => {
111                let lazy = $cdata.root.tables.$name.get(($cdata, $tcx), $def_id.index);
112                let value = if lazy.is_default() {
113                    &[] as &[_]
114                } else {
115                    $tcx.arena.alloc_from_iter(lazy.decode(($cdata, $tcx)))
116                };
117                value.process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
118            }
119        }
120    };
121    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => { table_direct }) => {
122        provide_one! {
123            $tcx, $def_id, $other, $cdata, $name => {
124                // We don't decode `table_direct`, since it's not a Lazy, but an actual value
125                $cdata
126                    .root
127                    .tables
128                    .$name
129                    .get(($cdata, $tcx), $def_id.index)
130                    .process_decoded($tcx, || panic!("{:?} does not have a {:?}", $def_id, stringify!($name)))
131            }
132        }
133    };
134    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => {
135        fn $name<'tcx>(
136            $tcx: TyCtxt<'tcx>,
137            def_id_arg: rustc_middle::query::queries::$name::Key<'tcx>,
138        ) -> rustc_middle::query::queries::$name::ProvidedValue<'tcx> {
139            let _prof_timer =
140                $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name)));
141
142            #[allow(unused_variables)]
143            let ($def_id, $other) = def_id_arg.into_args();
144            assert!(!$def_id.is_local());
145
146            // External query providers call `crate_hash` in order to register a dependency
147            // on the crate metadata. The exception is `crate_hash` itself, which obviously
148            // doesn't need to do this (and can't, as it would cause a query cycle).
149            use rustc_middle::dep_graph::dep_kinds;
150            if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
151                $tcx.ensure_ok().crate_hash($def_id.krate);
152            }
153
154            let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| {
155                c.get_crate_data($def_id.krate).cdata
156            });
157            let $cdata = crate::creader::CrateMetadataRef {
158                cdata: &cdata,
159                cstore: &CStore::from_tcx($tcx),
160            };
161
162            $compute
163        }
164    };
165}
166
167macro_rules! provide {
168    ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
169      $($name:ident => { $($compute:tt)* })*) => {
170        fn provide_extern(providers: &mut ExternProviders) {
171            $(provide_one! {
172                $tcx, $def_id, $other, $cdata, $name => { $($compute)* }
173            })*
174
175            *providers = ExternProviders {
176                $($name,)*
177                ..*providers
178            };
179        }
180    }
181}
182
183// small trait to work around different signature queries all being defined via
184// the macro above.
185trait IntoArgs {
186    type Other;
187    fn into_args(self) -> (DefId, Self::Other);
188}
189
190impl IntoArgs for DefId {
191    type Other = ();
192    fn into_args(self) -> (DefId, ()) {
193        (self, ())
194    }
195}
196
197impl IntoArgs for CrateNum {
198    type Other = ();
199    fn into_args(self) -> (DefId, ()) {
200        (self.as_def_id(), ())
201    }
202}
203
204impl IntoArgs for (CrateNum, DefId) {
205    type Other = DefId;
206    fn into_args(self) -> (DefId, DefId) {
207        (self.0.as_def_id(), self.1)
208    }
209}
210
211impl<'tcx> IntoArgs for ty::InstanceKind<'tcx> {
212    type Other = ();
213    fn into_args(self) -> (DefId, ()) {
214        (self.def_id(), ())
215    }
216}
217
218impl IntoArgs for (CrateNum, SimplifiedType) {
219    type Other = SimplifiedType;
220    fn into_args(self) -> (DefId, SimplifiedType) {
221        (self.0.as_def_id(), self.1)
222    }
223}
224
225provide! { tcx, def_id, other, cdata,
226    explicit_item_bounds => { table_defaulted_array }
227    explicit_item_self_bounds => { table_defaulted_array }
228    explicit_predicates_of => { table }
229    generics_of => { table }
230    inferred_outlives_of => { table_defaulted_array }
231    explicit_super_predicates_of => { table_defaulted_array }
232    explicit_implied_predicates_of => { table_defaulted_array }
233    type_of => { table }
234    type_alias_is_lazy => { table_direct }
235    variances_of => { table }
236    fn_sig => { table }
237    codegen_fn_attrs => { table }
238    impl_trait_header => { table }
239    const_param_default => { table }
240    object_lifetime_default => { table }
241    thir_abstract_const => { table }
242    optimized_mir => { table }
243    mir_for_ctfe => { table }
244    trivial_const => { table }
245    closure_saved_names_of_captured_variables => { table }
246    mir_coroutine_witnesses => { table }
247    promoted_mir => { table }
248    def_span => { table }
249    def_ident_span => { table }
250    lookup_stability => { table }
251    lookup_const_stability => { table }
252    lookup_default_body_stability => { table }
253    lookup_deprecation_entry => { table }
254    params_in_repr => { table }
255    def_kind => { cdata.def_kind(tcx, def_id.index) }
256    impl_parent => { table }
257    defaultness => { table_direct }
258    constness => { table_direct }
259    const_conditions => { table }
260    explicit_implied_const_bounds => { table_defaulted_array }
261    coerce_unsized_info => {
262        Ok(cdata
263            .root
264            .tables
265            .coerce_unsized_info
266            .get((cdata, tcx), def_id.index)
267            .map(|lazy| lazy.decode((cdata, tcx)))
268            .process_decoded(tcx, || panic!("{def_id:?} does not have coerce_unsized_info"))) }
269    mir_const_qualif => { table }
270    rendered_const => { table }
271    rendered_precise_capturing_args => { table }
272    asyncness => { table_direct }
273    fn_arg_idents => { table }
274    coroutine_kind => { table_direct }
275    coroutine_for_closure => { table }
276    coroutine_by_move_body_def_id => { table }
277    eval_static_initializer => {
278        Ok(cdata
279            .root
280            .tables
281            .eval_static_initializer
282            .get((cdata, tcx), def_id.index)
283            .map(|lazy| lazy.decode((cdata, tcx)))
284            .unwrap_or_else(|| panic!("{def_id:?} does not have eval_static_initializer")))
285    }
286    trait_def => { table }
287    deduced_param_attrs => {
288        // FIXME: `deduced_param_attrs` has some sketchy encoding settings,
289        // where we don't encode unless we're optimizing, doing codegen,
290        // and not incremental (see `encoder.rs`). I don't think this is right!
291        cdata
292            .root
293            .tables
294            .deduced_param_attrs
295            .get((cdata, tcx), def_id.index)
296            .map(|lazy| {
297                &*tcx.arena.alloc_from_iter(lazy.decode((cdata, tcx)))
298            })
299            .unwrap_or_default()
300    }
301    opaque_ty_origin => { table }
302    assumed_wf_types_for_rpitit => { table }
303    collect_return_position_impl_trait_in_trait_tys => {
304        Ok(cdata
305            .root
306            .tables
307            .trait_impl_trait_tys
308            .get((cdata, tcx), def_id.index)
309            .map(|lazy| lazy.decode((cdata, tcx)))
310            .process_decoded(tcx, || panic!("{def_id:?} does not have trait_impl_trait_tys")))
311    }
312
313    associated_types_for_impl_traits_in_trait_or_impl => { table }
314
315    visibility => { cdata.get_visibility(tcx, def_id.index) }
316    adt_def => { cdata.get_adt_def(tcx, def_id.index) }
317    adt_destructor => { table }
318    adt_async_destructor => { table }
319    associated_item_def_ids => {
320        tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(tcx, def_id.index))
321    }
322    associated_item => { cdata.get_associated_item(tcx, def_id.index) }
323    inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
324    attrs_for_def => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(tcx, def_id.index)) }
325    is_mir_available => { cdata.is_item_mir_available(tcx, def_id.index) }
326    is_ctfe_mir_available => { cdata.is_ctfe_mir_available(tcx, def_id.index) }
327    cross_crate_inlinable => { table_direct }
328
329    dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
330    is_private_dep => { cdata.private_dep }
331    is_panic_runtime => { cdata.root.panic_runtime }
332    is_compiler_builtins => { cdata.root.compiler_builtins }
333
334    // FIXME: to be replaced with externally_implementable_items below
335    has_global_allocator => { cdata.root.has_global_allocator }
336    // FIXME: to be replaced with externally_implementable_items below
337    has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
338    // FIXME: to be replaced with externally_implementable_items below
339    has_panic_handler => { cdata.root.has_panic_handler }
340
341    externally_implementable_items => {
342        cdata.get_externally_implementable_items(tcx)
343            .map(|(decl_did, (decl, impls))| (
344                decl_did,
345                (decl, impls.into_iter().collect())
346            )).collect()
347    }
348
349    is_profiler_runtime => { cdata.root.profiler_runtime }
350    required_panic_strategy => { cdata.root.required_panic_strategy }
351    panic_in_drop_strategy => { cdata.root.panic_in_drop_strategy }
352    extern_crate => { cdata.extern_crate.map(|c| &*tcx.arena.alloc(c)) }
353    is_no_builtins => { cdata.root.no_builtins }
354    symbol_mangling_version => { cdata.root.symbol_mangling_version }
355    specialization_enabled_in => { cdata.root.specialization_enabled_in }
356    reachable_non_generics => {
357        let reachable_non_generics = tcx
358            .exported_non_generic_symbols(cdata.cnum)
359            .iter()
360            .filter_map(|&(exported_symbol, export_info)| {
361                if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
362                    Some((def_id, export_info))
363                } else {
364                    None
365                }
366            })
367            .collect();
368
369        reachable_non_generics
370    }
371    native_libraries => { cdata.get_native_libraries(tcx).collect() }
372    foreign_modules => { cdata.get_foreign_modules(tcx).map(|m| (m.def_id, m)).collect() }
373    crate_hash => { cdata.root.header.hash }
374    crate_host_hash => { cdata.host_hash }
375    crate_name => { cdata.root.header.name }
376    num_extern_def_ids => { cdata.num_def_ids() }
377
378    extra_filename => { cdata.root.extra_filename.clone() }
379
380    traits => { tcx.arena.alloc_from_iter(cdata.get_traits(tcx)) }
381    trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls(tcx)) }
382    implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
383    crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
384
385    dep_kind => { cdata.dep_kind }
386    module_children => {
387        tcx.arena.alloc_from_iter(cdata.get_module_children(tcx, def_id.index))
388    }
389    lib_features => { cdata.get_lib_features(tcx) }
390    stability_implications => {
391        cdata.get_stability_implications(tcx).iter().copied().collect()
392    }
393    stripped_cfg_items => { cdata.get_stripped_cfg_items(tcx, cdata.cnum) }
394    intrinsic_raw => { cdata.get_intrinsic(tcx, def_id.index) }
395    defined_lang_items => { cdata.get_lang_items(tcx) }
396    diagnostic_items => { cdata.get_diagnostic_items(tcx) }
397    missing_lang_items => { cdata.get_missing_lang_items(tcx) }
398
399    missing_extern_crate_item => {
400        matches!(cdata.extern_crate, Some(extern_crate) if !extern_crate.is_direct())
401    }
402
403    used_crate_source => { Arc::clone(&cdata.source) }
404    debugger_visualizers => { cdata.get_debugger_visualizers(tcx) }
405
406    exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items(tcx)) }
407    stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls(tcx).collect()) }
408    exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) }
409    exported_generic_symbols => { cdata.exported_generic_symbols(tcx) }
410
411    crate_extern_paths => { cdata.source().paths().cloned().collect() }
412    expn_that_defined => { cdata.get_expn_that_defined(tcx, def_id.index) }
413    default_field => { cdata.get_default_field(tcx, def_id.index) }
414    is_doc_hidden => { cdata.get_attr_flags(tcx,def_id.index).contains(AttrFlags::IS_DOC_HIDDEN) }
415    doc_link_resolutions => { tcx.arena.alloc(cdata.get_doc_link_resolutions(tcx, def_id.index)) }
416    doc_link_traits_in_scope => {
417        tcx.arena.alloc_from_iter(cdata.get_doc_link_traits_in_scope(tcx, def_id.index))
418    }
419    anon_const_kind => { table }
420    const_of_item => { table }
421}
422
423pub(in crate::rmeta) fn provide(providers: &mut Providers) {
424    provide_cstore_hooks(providers);
425    providers.queries = rustc_middle::query::Providers {
426        allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
427        alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
428        is_private_dep: |_tcx, LocalCrate| false,
429        native_library: |tcx, id| {
430            tcx.native_libraries(id.krate)
431                .iter()
432                .filter(|lib| native_libs::relevant_lib(tcx.sess, lib))
433                .find(|lib| {
434                    let Some(fm_id) = lib.foreign_module else {
435                        return false;
436                    };
437                    let map = tcx.foreign_modules(id.krate);
438                    map.get(&fm_id)
439                        .expect("failed to find foreign module")
440                        .foreign_items
441                        .contains(&id)
442                })
443        },
444        native_libraries: native_libs::collect,
445        foreign_modules: foreign_modules::collect,
446        externally_implementable_items: eii::collect,
447
448        // Returns a map from a sufficiently visible external item (i.e., an
449        // external item that is visible from at least one local module) to a
450        // sufficiently visible parent (considering modules that re-export the
451        // external item to be parents).
452        visible_parent_map: |tcx, ()| {
453            use std::collections::hash_map::Entry;
454            use std::collections::vec_deque::VecDeque;
455
456            let mut visible_parent_map: DefIdMap<DefId> = Default::default();
457            // This is a secondary visible_parent_map, storing the DefId of
458            // parents that re-export the child as `_` or module parents
459            // which are `#[doc(hidden)]`. Since we prefer paths that don't
460            // do this, merge this map at the end, only if we're missing
461            // keys from the former.
462            // This is a rudimentary check that does not catch all cases,
463            // just the easiest.
464            let mut fallback_map: Vec<(DefId, DefId)> = Default::default();
465
466            // Issue 46112: We want the map to prefer the shortest
467            // paths when reporting the path to an item. Therefore we
468            // build up the map via a breadth-first search (BFS),
469            // which naturally yields minimal-length paths.
470            //
471            // Note that it needs to be a BFS over the whole forest of
472            // crates, not just each individual crate; otherwise you
473            // only get paths that are locally minimal with respect to
474            // whatever crate we happened to encounter first in this
475            // traversal, but not globally minimal across all crates.
476            let bfs_queue = &mut VecDeque::new();
477
478            for &cnum in tcx.crates(()) {
479                // Ignore crates without a corresponding local `extern crate` item.
480                if tcx.missing_extern_crate_item(cnum) {
481                    continue;
482                }
483
484                bfs_queue.push_back(cnum.as_def_id());
485            }
486
487            let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
488                if !child.vis.is_public() {
489                    return;
490                }
491
492                if let Some(def_id) = child.res.opt_def_id() {
493                    if child.ident.name == kw::Underscore {
494                        fallback_map.push((def_id, parent));
495                        return;
496                    }
497
498                    if tcx.is_doc_hidden(parent) {
499                        fallback_map.push((def_id, parent));
500                        return;
501                    }
502
503                    match visible_parent_map.entry(def_id) {
504                        Entry::Occupied(mut entry) => {
505                            // If `child` is defined in crate `cnum`, ensure
506                            // that it is mapped to a parent in `cnum`.
507                            if def_id.is_local() && entry.get().is_local() {
508                                entry.insert(parent);
509                            }
510                        }
511                        Entry::Vacant(entry) => {
512                            entry.insert(parent);
513                            if child.res.module_like_def_id().is_some() {
514                                bfs_queue.push_back(def_id);
515                            }
516                        }
517                    }
518                }
519            };
520
521            while let Some(def) = bfs_queue.pop_front() {
522                for child in tcx.module_children(def).iter() {
523                    add_child(bfs_queue, child, def);
524                }
525            }
526
527            // Fill in any missing entries with the less preferable path.
528            // If this path re-exports the child as `_`, we still use this
529            // path in a diagnostic that suggests importing `::*`.
530
531            for (child, parent) in fallback_map {
532                visible_parent_map.entry(child).or_insert(parent);
533            }
534
535            visible_parent_map
536        },
537
538        dependency_formats: |tcx, ()| Arc::new(crate::dependency_format::calculate(tcx)),
539        has_global_allocator: |tcx, LocalCrate| CStore::from_tcx(tcx).has_global_allocator(),
540        has_alloc_error_handler: |tcx, LocalCrate| CStore::from_tcx(tcx).has_alloc_error_handler(),
541        postorder_cnums: |tcx, ()| {
542            tcx.arena.alloc_from_iter(
543                CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE).into_iter(),
544            )
545        },
546        crates: |tcx, ()| {
547            // The list of loaded crates is now frozen in query cache,
548            // so make sure cstore is not mutably accessed from here on.
549            tcx.untracked().cstore.freeze();
550            tcx.arena.alloc_from_iter(CStore::from_tcx(tcx).iter_crate_data().map(|(cnum, _)| cnum))
551        },
552        used_crates: |tcx, ()| {
553            // The list of loaded crates is now frozen in query cache,
554            // so make sure cstore is not mutably accessed from here on.
555            tcx.untracked().cstore.freeze();
556            tcx.arena.alloc_from_iter(
557                CStore::from_tcx(tcx)
558                    .iter_crate_data()
559                    .filter_map(|(cnum, data)| data.used().then_some(cnum)),
560            )
561        },
562        ..providers.queries
563    };
564    provide_extern(&mut providers.extern_queries);
565}
566
567impl CStore {
568    pub fn ctor_untracked(&self, tcx: TyCtxt<'_>, def: DefId) -> Option<(CtorKind, DefId)> {
569        self.get_crate_data(def.krate).get_ctor(tcx, def.index)
570    }
571
572    pub fn load_macro_untracked(&self, tcx: TyCtxt<'_>, id: DefId) -> LoadedMacro {
573        let sess = tcx.sess;
574        let _prof_timer = sess.prof.generic_activity("metadata_load_macro");
575
576        let data = self.get_crate_data(id.krate);
577        if data.root.is_proc_macro_crate() {
578            LoadedMacro::ProcMacro(data.load_proc_macro(tcx, id.index))
579        } else {
580            LoadedMacro::MacroDef {
581                def: data.get_macro(tcx, id.index),
582                ident: data.item_ident(tcx, id.index),
583                attrs: data.get_item_attrs(tcx, id.index).collect(),
584                span: data.get_span(tcx, id.index),
585                edition: data.root.edition,
586            }
587        }
588    }
589
590    pub fn def_span_untracked(&self, tcx: TyCtxt<'_>, def_id: DefId) -> Span {
591        self.get_crate_data(def_id.krate).get_span(tcx, def_id.index)
592    }
593
594    pub fn def_kind_untracked(&self, tcx: TyCtxt<'_>, def: DefId) -> DefKind {
595        self.get_crate_data(def.krate).def_kind(tcx, def.index)
596    }
597
598    pub fn expn_that_defined_untracked(&self, tcx: TyCtxt<'_>, def_id: DefId) -> ExpnId {
599        self.get_crate_data(def_id.krate).get_expn_that_defined(tcx, def_id.index)
600    }
601
602    pub fn ambig_module_children_untracked(
603        &self,
604        tcx: TyCtxt<'_>,
605        def_id: DefId,
606    ) -> impl Iterator<Item = AmbigModChild> {
607        self.get_crate_data(def_id.krate).get_ambig_module_children(tcx, def_id.index)
608    }
609
610    /// Only public-facing way to traverse all the definitions in a non-local crate.
611    /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>.
612    /// See <https://github.com/rust-lang/rust/pull/85889> for context.
613    pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
614        self.get_crate_data(cnum).num_def_ids()
615    }
616
617    pub fn get_proc_macro_quoted_span_untracked(
618        &self,
619        tcx: TyCtxt<'_>,
620        cnum: CrateNum,
621        id: usize,
622    ) -> Span {
623        self.get_crate_data(cnum).get_proc_macro_quoted_span(tcx, id)
624    }
625
626    pub fn set_used_recursively(&mut self, tcx: TyCtxt<'_>, cnum: CrateNum) {
627        let cmeta = self.get_crate_data_mut(cnum);
628        if !cmeta.used {
629            cmeta.used = true;
630            let dependencies = mem::take(&mut cmeta.dependencies);
631            for &dep_cnum in &dependencies {
632                self.set_used_recursively(tcx, dep_cnum);
633            }
634            self.get_crate_data_mut(cnum).dependencies = dependencies;
635        }
636    }
637
638    /// Track how an extern crate has been loaded. Called after resolving an import in the local crate.
639    ///
640    /// * the `name` is for [`Self::set_resolved_extern_crate_name`] saving `--extern name=`
641    /// * `extern_crate` is for diagnostics
642    pub(crate) fn update_extern_crate(
643        &mut self,
644        cnum: CrateNum,
645        name: Symbol,
646        extern_crate: ExternCrate,
647    ) {
648        debug_assert_eq!(
649            extern_crate.dependency_of, LOCAL_CRATE,
650            "this function should not be called on transitive dependencies"
651        );
652        self.set_resolved_extern_crate_name(name, cnum);
653        self.update_transitive_extern_crate_diagnostics(cnum, extern_crate);
654    }
655
656    /// `CrateMetadata` uses `ExternCrate` only for diagnostics
657    fn update_transitive_extern_crate_diagnostics(
658        &mut self,
659        cnum: CrateNum,
660        extern_crate: ExternCrate,
661    ) {
662        let cmeta = self.get_crate_data_mut(cnum);
663        if cmeta.update_extern_crate_diagnostics(extern_crate) {
664            // Propagate the extern crate info to dependencies if it was updated.
665            let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
666            let dependencies = mem::take(&mut cmeta.dependencies);
667            for &dep_cnum in &dependencies {
668                self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate);
669            }
670            self.get_crate_data_mut(cnum).dependencies = dependencies;
671        }
672    }
673}
674
675impl CrateStore for CStore {
676    fn as_any(&self) -> &dyn Any {
677        self
678    }
679    fn untracked_as_any(&mut self) -> &mut dyn Any {
680        self
681    }
682
683    fn crate_name(&self, cnum: CrateNum) -> Symbol {
684        self.get_crate_data(cnum).root.header.name
685    }
686
687    fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId {
688        self.get_crate_data(cnum).root.stable_crate_id
689    }
690
691    /// Returns the `DefKey` for a given `DefId`. This indicates the
692    /// parent `DefId` as well as some idea of what kind of data the
693    /// `DefId` refers to.
694    fn def_key(&self, def: DefId) -> DefKey {
695        self.get_crate_data(def.krate).def_key(def.index)
696    }
697
698    fn def_path(&self, def: DefId) -> DefPath {
699        self.get_crate_data(def.krate).def_path(def.index)
700    }
701
702    fn def_path_hash(&self, def: DefId) -> DefPathHash {
703        self.get_crate_data(def.krate).def_path_hash(def.index)
704    }
705}
706
707fn provide_cstore_hooks(providers: &mut Providers) {
708    providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| {
709        // If this is a DefPathHash from an upstream crate, let the CrateStore map
710        // it to a DefId.
711        let cstore = CStore::from_tcx(tcx);
712        let cnum = *tcx
713            .untracked()
714            .stable_crate_ids
715            .read()
716            .get(&stable_crate_id)
717            .unwrap_or_else(|| bug!("uninterned StableCrateId: {stable_crate_id:?}"));
718        assert_ne!(cnum, LOCAL_CRATE);
719        let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash)?;
720        Some(DefId { krate: cnum, index: def_index })
721    };
722
723    providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| {
724        let cstore = CStore::from_tcx(tcx);
725        cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx, index_guess, hash)
726    };
727    providers.hooks.import_source_files = |tcx, cnum| {
728        let cstore = CStore::from_tcx(tcx);
729        let cdata = cstore.get_crate_data(cnum);
730        for file_index in 0..cdata.root.source_map.size() {
731            cdata.imported_source_file(tcx, file_index as u32);
732        }
733    };
734}