Skip to main content

rustc_passes/
canonical_symbols.rs

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