Skip to main content

rustc_passes/
canonical_symbols.rs

1use rustc_hir::attrs::CanonicalSymbols;
2use rustc_hir::{ForeignItemId, find_attr};
3use rustc_middle::query::{LocalCrate, Providers};
4use rustc_middle::ty::{Instance, List, TyCtxt};
5use rustc_span::def_id::{DefId, LOCAL_CRATE};
6use rustc_span::{Symbol, sym};
7
8use crate::diagnostics::DuplicateCanonicalSymbolInCrate;
9
10fn observe_item<'tcx>(
11    tcx: TyCtxt<'tcx>,
12    canonical_symbols: &mut CanonicalSymbols,
13    fid: ForeignItemId,
14) {
15    let attrs = tcx.hir_attrs(fid.owner_id.into());
16    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(RustcCanonicalSymbol) =>
                            {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }.is_some()
}find_attr!(attrs, RustcCanonicalSymbol) {
17        let did = fid.owner_id.def_id;
18        let instance = Instance::new_raw(did.to_def_id(), List::identity_for_item(tcx, did));
19        let symbol_name = tcx.symbol_name(instance);
20        let symbol_name = Symbol::intern(symbol_name.name);
21
22        // insert into our table
23        collect_item(tcx, canonical_symbols, symbol_name, fid.owner_id.to_def_id());
24    }
25}
26
27fn collect_item(
28    tcx: TyCtxt<'_>,
29    canonical_symbols: &mut CanonicalSymbols,
30    symbol: Symbol,
31    item_def_id: DefId,
32) {
33    if let Some(original_def_id) = canonical_symbols.set(symbol, item_def_id) {
34        report_duplicate_item(tcx, symbol, original_def_id, item_def_id);
35    }
36}
37
38fn report_duplicate_item(
39    tcx: TyCtxt<'_>,
40    name: Symbol,
41    original_def_id: DefId,
42    item_def_id: DefId,
43) {
44    let orig_span = tcx.hir_span_if_local(original_def_id);
45    let duplicate_span = tcx.hir_span_if_local(item_def_id);
46    tcx.dcx().emit_err(DuplicateCanonicalSymbolInCrate {
47        duplicate_span,
48        orig_span,
49        crate_name: tcx.crate_name(item_def_id.krate),
50        orig_crate_name: tcx.crate_name(original_def_id.krate),
51        different_crates: (item_def_id.krate != original_def_id.krate),
52        name,
53    });
54}
55
56/// Traverse and collect the canonical symbols in the current crate
57fn canonical_symbols(tcx: TyCtxt<'_>, _: LocalCrate) -> CanonicalSymbols {
58    // Initialize the collector.
59    let mut canonical_symbols = CanonicalSymbols::new();
60
61    // Optimization: can this crate even define canonical items?
62    // (But do not mark `rustc_attrs` as used while doing so)
63    if tcx.features().enabled_features().contains(&sym::rustc_attrs) {
64        // Collect canonical symbols in this crate.
65        let crate_items = tcx.hir_crate_items(());
66        for id in crate_items.foreign_items() {
67            observe_item(tcx, &mut canonical_symbols, id);
68        }
69    }
70    canonical_symbols
71}
72
73/// Traverse and collect all the canonical symbols in all crates.
74fn all_canonical_symbols(tcx: TyCtxt<'_>, (): ()) -> CanonicalSymbols {
75    // Initialize the collector.
76    let mut items = CanonicalSymbols::new();
77
78    // Collect all canonical symbols
79    for cnum in tcx.crates(()).iter().copied().chain(std::iter::once(LOCAL_CRATE)) {
80        for cs in tcx.canonical_symbols(cnum).iter() {
81            collect_item(tcx, &mut items, cs.symbol, cs.def_id);
82        }
83    }
84
85    items
86}
87
88pub(crate) fn provide(providers: &mut Providers) {
89    providers.canonical_symbols = canonical_symbols;
90    providers.all_canonical_symbols = all_canonical_symbols;
91}