rustc_metadata/
creader.rs

1//! Validates all used crates and extern libraries and loads their metadata
2
3use std::error::Error;
4use std::path::Path;
5use std::str::FromStr;
6use std::time::Duration;
7use std::{cmp, env, iter};
8
9use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name};
10use rustc_ast::{self as ast, *};
11use rustc_data_structures::fx::FxHashSet;
12use rustc_data_structures::owned_slice::OwnedSlice;
13use rustc_data_structures::svh::Svh;
14use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
15use rustc_expand::base::SyntaxExtension;
16use rustc_fs_util::try_canonicalize;
17use rustc_hir as hir;
18use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId};
19use rustc_hir::definitions::Definitions;
20use rustc_index::IndexVec;
21use rustc_middle::bug;
22use rustc_middle::ty::data_structures::IndexSet;
23use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
24use rustc_proc_macro::bridge::client::ProcMacro;
25use rustc_session::Session;
26use rustc_session::config::{
27    CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers,
28    TargetModifier,
29};
30use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
31use rustc_session::lint::{self, BuiltinLintDiag};
32use rustc_session::output::validate_crate_name;
33use rustc_session::search_paths::PathKind;
34use rustc_span::edition::Edition;
35use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
36use rustc_target::spec::{PanicStrategy, Target};
37use tracing::{debug, info, trace};
38
39use crate::errors;
40use crate::locator::{CrateError, CrateLocator, CratePaths, CrateRejections};
41use crate::rmeta::{
42    CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
43};
44
45/// The backend's way to give the crate store access to the metadata in a library.
46/// Note that it returns the raw metadata bytes stored in the library file, whether
47/// it is compressed, uncompressed, some weird mix, etc.
48/// rmeta files are backend independent and not handled here.
49pub trait MetadataLoader {
50    fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
51    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
52}
53
54pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
55
56pub struct CStore {
57    metadata_loader: Box<MetadataLoaderDyn>,
58
59    metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>,
60    injected_panic_runtime: Option<CrateNum>,
61    /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
62    /// If the above is true, then this field denotes the kind of the found allocator.
63    allocator_kind: Option<AllocatorKind>,
64    /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
65    /// If the above is true, then this field denotes the kind of the found allocator.
66    alloc_error_handler_kind: Option<AllocatorKind>,
67    /// This crate has a `#[global_allocator]` item.
68    has_global_allocator: bool,
69    /// This crate has a `#[alloc_error_handler]` item.
70    has_alloc_error_handler: bool,
71
72    /// Unused externs of the crate
73    unused_externs: Vec<Symbol>,
74
75    used_extern_options: FxHashSet<Symbol>,
76}
77
78impl std::fmt::Debug for CStore {
79    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80        f.debug_struct("CStore").finish_non_exhaustive()
81    }
82}
83
84pub enum LoadedMacro {
85    MacroDef {
86        def: MacroDef,
87        ident: Ident,
88        attrs: Vec<hir::Attribute>,
89        span: Span,
90        edition: Edition,
91    },
92    ProcMacro(SyntaxExtension),
93}
94
95pub(crate) struct Library {
96    pub source: CrateSource,
97    pub metadata: MetadataBlob,
98}
99
100enum LoadResult {
101    Previous(CrateNum),
102    Loaded(Library),
103}
104
105/// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
106#[derive(Clone, Copy)]
107pub(crate) struct CrateMetadataRef<'a> {
108    pub cdata: &'a CrateMetadata,
109    pub cstore: &'a CStore,
110}
111
112impl std::ops::Deref for CrateMetadataRef<'_> {
113    type Target = CrateMetadata;
114
115    fn deref(&self) -> &Self::Target {
116        self.cdata
117    }
118}
119
120struct CrateDump<'a>(&'a CStore);
121
122impl<'a> std::fmt::Debug for CrateDump<'a> {
123    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        writeln!(fmt, "resolved crates:")?;
125        for (cnum, data) in self.0.iter_crate_data() {
126            writeln!(fmt, "  name: {}", data.name())?;
127            writeln!(fmt, "  cnum: {cnum}")?;
128            writeln!(fmt, "  hash: {}", data.hash())?;
129            writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
130            writeln!(fmt, "  priv: {:?}", data.is_private_dep())?;
131            let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
132            if let Some(dylib) = dylib {
133                writeln!(fmt, "  dylib: {}", dylib.0.display())?;
134            }
135            if let Some(rlib) = rlib {
136                writeln!(fmt, "   rlib: {}", rlib.0.display())?;
137            }
138            if let Some(rmeta) = rmeta {
139                writeln!(fmt, "   rmeta: {}", rmeta.0.display())?;
140            }
141            if let Some(sdylib_interface) = sdylib_interface {
142                writeln!(fmt, "   sdylib interface: {}", sdylib_interface.0.display())?;
143            }
144        }
145        Ok(())
146    }
147}
148
149/// Reason that a crate is being sourced as a dependency.
150#[derive(Clone, Copy)]
151enum CrateOrigin<'a> {
152    /// This crate was a dependency of another crate.
153    IndirectDependency {
154        /// Where this dependency was included from.
155        dep_root: &'a CratePaths,
156        /// True if the parent is private, meaning the dependent should also be private.
157        parent_private: bool,
158        /// Dependency info about this crate.
159        dep: &'a CrateDep,
160    },
161    /// Injected by `rustc`.
162    Injected,
163    /// Provided by `extern crate foo` or as part of the extern prelude.
164    Extern,
165}
166
167impl<'a> CrateOrigin<'a> {
168    /// Return the dependency root, if any.
169    fn dep_root(&self) -> Option<&'a CratePaths> {
170        match self {
171            CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
172            _ => None,
173        }
174    }
175
176    /// Return dependency information, if any.
177    fn dep(&self) -> Option<&'a CrateDep> {
178        match self {
179            CrateOrigin::IndirectDependency { dep, .. } => Some(dep),
180            _ => None,
181        }
182    }
183
184    /// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the
185    /// dependency is not private, `None` if it could not be determined.
186    fn private_dep(&self) -> Option<bool> {
187        match self {
188            CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
189                Some(dep.is_private || *parent_private)
190            }
191            _ => None,
192        }
193    }
194}
195
196impl CStore {
197    pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
198        FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
199            cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
200        })
201    }
202
203    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {
204        FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
205            cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
206        })
207    }
208
209    fn intern_stable_crate_id<'tcx>(
210        &mut self,
211        tcx: TyCtxt<'tcx>,
212        root: &CrateRoot,
213    ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
214        assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
215        let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
216            // Check for (potential) conflicts with the local crate
217            if existing == LOCAL_CRATE {
218                CrateError::SymbolConflictsCurrent(root.name())
219            } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
220            {
221                let crate_name0 = root.name();
222                CrateError::StableCrateIdCollision(crate_name0, crate_name1)
223            } else {
224                CrateError::NotFound(root.name())
225            }
226        })?;
227
228        self.metas.push(None);
229        Ok(num)
230    }
231
232    pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
233        self.metas[cnum].is_some()
234    }
235
236    pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
237        let cdata = self.metas[cnum]
238            .as_ref()
239            .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
240        CrateMetadataRef { cdata, cstore: self }
241    }
242
243    pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {
244        self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
245    }
246
247    fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
248        assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
249        self.metas[cnum] = Some(Box::new(data));
250    }
251
252    pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
253        self.metas
254            .iter_enumerated()
255            .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
256    }
257
258    fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {
259        if !deps.contains(&cnum) {
260            let data = self.get_crate_data(cnum);
261            for dep in data.dependencies() {
262                if dep != cnum {
263                    self.push_dependencies_in_postorder(deps, dep);
264                }
265            }
266
267            deps.insert(cnum);
268        }
269    }
270
271    pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> IndexSet<CrateNum> {
272        let mut deps = IndexSet::default();
273        if cnum == LOCAL_CRATE {
274            for (cnum, _) in self.iter_crate_data() {
275                self.push_dependencies_in_postorder(&mut deps, cnum);
276            }
277        } else {
278            self.push_dependencies_in_postorder(&mut deps, cnum);
279        }
280        deps
281    }
282
283    pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
284        self.injected_panic_runtime
285    }
286
287    pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {
288        self.allocator_kind
289    }
290
291    pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
292        self.alloc_error_handler_kind
293    }
294
295    pub(crate) fn has_global_allocator(&self) -> bool {
296        self.has_global_allocator
297    }
298
299    pub(crate) fn has_alloc_error_handler(&self) -> bool {
300        self.has_alloc_error_handler
301    }
302
303    pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
304        let json_unused_externs = tcx.sess.opts.json_unused_externs;
305
306        // We put the check for the option before the lint_level_at_node call
307        // because the call mutates internal state and introducing it
308        // leads to some ui tests failing.
309        if !json_unused_externs.is_enabled() {
310            return;
311        }
312        let level = tcx
313            .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
314            .level;
315        if level != lint::Level::Allow {
316            let unused_externs =
317                self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
318            let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
319            tcx.dcx().emit_unused_externs(level, json_unused_externs.is_loud(), &unused_externs);
320        }
321    }
322
323    fn report_target_modifiers_extended(
324        tcx: TyCtxt<'_>,
325        krate: &Crate,
326        mods: &TargetModifiers,
327        dep_mods: &TargetModifiers,
328        data: &CrateMetadata,
329    ) {
330        let span = krate.spans.inner_span.shrink_to_lo();
331        let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
332        let local_crate = tcx.crate_name(LOCAL_CRATE);
333        let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
334        let report_diff = |prefix: &String,
335                           opt_name: &String,
336                           flag_local_value: Option<&String>,
337                           flag_extern_value: Option<&String>| {
338            if allowed_flag_mismatches.contains(&opt_name) {
339                return;
340            }
341            let extern_crate = data.name();
342            let flag_name = opt_name.clone();
343            let flag_name_prefixed = format!("-{}{}", prefix, opt_name);
344
345            match (flag_local_value, flag_extern_value) {
346                (Some(local_value), Some(extern_value)) => {
347                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
348                        span,
349                        extern_crate,
350                        local_crate,
351                        flag_name,
352                        flag_name_prefixed,
353                        local_value: local_value.to_string(),
354                        extern_value: extern_value.to_string(),
355                    })
356                }
357                (None, Some(extern_value)) => {
358                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed {
359                        span,
360                        extern_crate,
361                        local_crate,
362                        flag_name,
363                        flag_name_prefixed,
364                        extern_value: extern_value.to_string(),
365                    })
366                }
367                (Some(local_value), None) => {
368                    tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed {
369                        span,
370                        extern_crate,
371                        local_crate,
372                        flag_name,
373                        flag_name_prefixed,
374                        local_value: local_value.to_string(),
375                    })
376                }
377                (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),
378            };
379        };
380        let mut it1 = mods.iter().map(tmod_extender);
381        let mut it2 = dep_mods.iter().map(tmod_extender);
382        let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
383        let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
384        loop {
385            left_name_val = left_name_val.or_else(|| it1.next());
386            right_name_val = right_name_val.or_else(|| it2.next());
387            match (&left_name_val, &right_name_val) {
388                (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
389                    cmp::Ordering::Equal => {
390                        if l.0.tech_value != r.0.tech_value {
391                            report_diff(
392                                &l.0.prefix,
393                                &l.0.name,
394                                Some(&l.1.value_name),
395                                Some(&r.1.value_name),
396                            );
397                        }
398                        left_name_val = None;
399                        right_name_val = None;
400                    }
401                    cmp::Ordering::Greater => {
402                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
403                        right_name_val = None;
404                    }
405                    cmp::Ordering::Less => {
406                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
407                        left_name_val = None;
408                    }
409                },
410                (Some(l), None) => {
411                    report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
412                    left_name_val = None;
413                }
414                (None, Some(r)) => {
415                    report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
416                    right_name_val = None;
417                }
418                (None, None) => break,
419            }
420        }
421    }
422
423    pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
424        for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
425            if !OptionsTargetModifiers::is_target_modifier(flag_name) {
426                tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
427                    span: krate.spans.inner_span.shrink_to_lo(),
428                    flag_name: flag_name.clone(),
429                });
430            }
431        }
432        let mods = tcx.sess.opts.gather_target_modifiers();
433        for (_cnum, data) in self.iter_crate_data() {
434            if data.is_proc_macro_crate() {
435                continue;
436            }
437            let dep_mods = data.target_modifiers();
438            if mods != dep_mods {
439                Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
440            }
441        }
442    }
443
444    // Report about async drop types in dependency if async drop feature is disabled
445    pub fn report_incompatible_async_drop_feature(&self, tcx: TyCtxt<'_>, krate: &Crate) {
446        if tcx.features().async_drop() {
447            return;
448        }
449        for (_cnum, data) in self.iter_crate_data() {
450            if data.is_proc_macro_crate() {
451                continue;
452            }
453            if data.has_async_drops() {
454                let extern_crate = data.name();
455                let local_crate = tcx.crate_name(LOCAL_CRATE);
456                tcx.dcx().emit_warn(errors::AsyncDropTypesInDependency {
457                    span: krate.spans.inner_span.shrink_to_lo(),
458                    extern_crate,
459                    local_crate,
460                });
461            }
462        }
463    }
464
465    pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
466        CStore {
467            metadata_loader,
468            // We add an empty entry for LOCAL_CRATE (which maps to zero) in
469            // order to make array indices in `metas` match with the
470            // corresponding `CrateNum`. This first entry will always remain
471            // `None`.
472            metas: IndexVec::from_iter(iter::once(None)),
473            injected_panic_runtime: None,
474            allocator_kind: None,
475            alloc_error_handler_kind: None,
476            has_global_allocator: false,
477            has_alloc_error_handler: false,
478            unused_externs: Vec::new(),
479            used_extern_options: Default::default(),
480        }
481    }
482
483    fn existing_match(
484        &self,
485        externs: &Externs,
486        name: Symbol,
487        hash: Option<Svh>,
488        kind: PathKind,
489    ) -> Option<CrateNum> {
490        for (cnum, data) in self.iter_crate_data() {
491            if data.name() != name {
492                trace!("{} did not match {}", data.name(), name);
493                continue;
494            }
495
496            match hash {
497                Some(hash) if hash == data.hash() => return Some(cnum),
498                Some(hash) => {
499                    debug!("actual hash {} did not match expected {}", hash, data.hash());
500                    continue;
501                }
502                None => {}
503            }
504
505            // When the hash is None we're dealing with a top-level dependency
506            // in which case we may have a specification on the command line for
507            // this library. Even though an upstream library may have loaded
508            // something of the same name, we have to make sure it was loaded
509            // from the exact same location as well.
510            //
511            // We're also sure to compare *paths*, not actual byte slices. The
512            // `source` stores paths which are normalized which may be different
513            // from the strings on the command line.
514            let source = self.get_crate_data(cnum).cdata.source();
515            if let Some(entry) = externs.get(name.as_str()) {
516                // Only use `--extern crate_name=path` here, not `--extern crate_name`.
517                if let Some(mut files) = entry.files() {
518                    if files.any(|l| {
519                        let l = l.canonicalized();
520                        source.dylib.as_ref().map(|(p, _)| p) == Some(l)
521                            || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
522                            || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
523                    }) {
524                        return Some(cnum);
525                    }
526                }
527                continue;
528            }
529
530            // Alright, so we've gotten this far which means that `data` has the
531            // right name, we don't have a hash, and we don't have a --extern
532            // pointing for ourselves. We're still not quite yet done because we
533            // have to make sure that this crate was found in the crate lookup
534            // path (this is a top-level dependency) as we don't want to
535            // implicitly load anything inside the dependency lookup path.
536            let prev_kind = source
537                .dylib
538                .as_ref()
539                .or(source.rlib.as_ref())
540                .or(source.rmeta.as_ref())
541                .expect("No sources for crate")
542                .1;
543            if kind.matches(prev_kind) {
544                return Some(cnum);
545            } else {
546                debug!(
547                    "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
548                    name, kind, prev_kind
549                );
550            }
551        }
552
553        None
554    }
555
556    /// Determine whether a dependency should be considered private.
557    ///
558    /// Dependencies are private if they get extern option specified, e.g. `--extern priv:mycrate`.
559    /// This is stored in metadata, so `private_dep`  can be correctly set during load. A `Some`
560    /// value for `private_dep` indicates that the crate is known to be private or public (note
561    /// that any `None` or `Some(false)` use of the same crate will make it public).
562    ///
563    /// Sometimes the directly dependent crate is not specified by `--extern`, in this case,
564    /// `private-dep` is none during loading. This is equivalent to the scenario where the
565    /// command parameter is set to `public-dependency`
566    fn is_private_dep(
567        &self,
568        externs: &Externs,
569        name: Symbol,
570        private_dep: Option<bool>,
571        origin: CrateOrigin<'_>,
572    ) -> bool {
573        if matches!(origin, CrateOrigin::Injected) {
574            return true;
575        }
576
577        let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep);
578        match (extern_private, private_dep) {
579            // Explicit non-private via `--extern`, explicit non-private from metadata, or
580            // unspecified with default to public.
581            (Some(false), _) | (_, Some(false)) | (None, None) => false,
582            // Marked private via `--extern priv:mycrate` or in metadata.
583            (Some(true) | None, Some(true) | None) => true,
584        }
585    }
586
587    fn register_crate<'tcx>(
588        &mut self,
589        tcx: TyCtxt<'tcx>,
590        host_lib: Option<Library>,
591        origin: CrateOrigin<'_>,
592        lib: Library,
593        dep_kind: CrateDepKind,
594        name: Symbol,
595        private_dep: Option<bool>,
596    ) -> Result<CrateNum, CrateError> {
597        let _prof_timer =
598            tcx.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
599
600        let Library { source, metadata } = lib;
601        let crate_root = metadata.get_root();
602        let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
603        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
604
605        // Claim this crate number and cache it
606        let feed = self.intern_stable_crate_id(tcx, &crate_root)?;
607        let cnum = feed.key();
608
609        info!(
610            "register crate `{}` (cnum = {}. private_dep = {})",
611            crate_root.name(),
612            cnum,
613            private_dep
614        );
615
616        // Maintain a reference to the top most crate.
617        // Stash paths for top-most crate locally if necessary.
618        let crate_paths;
619        let dep_root = if let Some(dep_root) = origin.dep_root() {
620            dep_root
621        } else {
622            crate_paths = CratePaths::new(crate_root.name(), source.clone());
623            &crate_paths
624        };
625
626        let cnum_map = self.resolve_crate_deps(
627            tcx,
628            dep_root,
629            &crate_root,
630            &metadata,
631            cnum,
632            dep_kind,
633            private_dep,
634        )?;
635
636        let raw_proc_macros = if crate_root.is_proc_macro_crate() {
637            let temp_root;
638            let (dlsym_source, dlsym_root) = match &host_lib {
639                Some(host_lib) => (&host_lib.source, {
640                    temp_root = host_lib.metadata.get_root();
641                    &temp_root
642                }),
643                None => (&source, &crate_root),
644            };
645            let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
646            Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?)
647        } else {
648            None
649        };
650
651        let crate_metadata = CrateMetadata::new(
652            tcx.sess,
653            self,
654            metadata,
655            crate_root,
656            raw_proc_macros,
657            cnum,
658            cnum_map,
659            dep_kind,
660            source,
661            private_dep,
662            host_hash,
663        );
664
665        self.set_crate_data(cnum, crate_metadata);
666
667        Ok(cnum)
668    }
669
670    fn load_proc_macro<'a, 'b>(
671        &self,
672        sess: &'a Session,
673        locator: &mut CrateLocator<'b>,
674        crate_rejections: &mut CrateRejections,
675        path_kind: PathKind,
676        host_hash: Option<Svh>,
677    ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
678    where
679        'a: 'b,
680    {
681        if sess.opts.unstable_opts.dual_proc_macros {
682            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
683            // affect the error message we emit
684            let mut proc_macro_locator = locator.clone();
685
686            // Try to load a proc macro
687            proc_macro_locator.for_target_proc_macro(sess, path_kind);
688
689            // Load the proc macro crate for the target
690            let target_result =
691                match self.load(&mut proc_macro_locator, &mut CrateRejections::default())? {
692                    Some(LoadResult::Previous(cnum)) => {
693                        return Ok(Some((LoadResult::Previous(cnum), None)));
694                    }
695                    Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
696                    None => return Ok(None),
697                };
698
699            // Use the existing crate_rejections as we want the error message to be affected by
700            // loading the host proc macro.
701            *crate_rejections = CrateRejections::default();
702
703            // Load the proc macro crate for the host
704            locator.for_proc_macro(sess, path_kind);
705
706            locator.hash = host_hash;
707
708            let Some(host_result) = self.load(locator, crate_rejections)? else {
709                return Ok(None);
710            };
711
712            let host_result = match host_result {
713                LoadResult::Previous(..) => {
714                    panic!("host and target proc macros must be loaded in lock-step")
715                }
716                LoadResult::Loaded(library) => library,
717            };
718            Ok(Some((target_result.unwrap(), Some(host_result))))
719        } else {
720            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't
721            // affect the error message we emit
722            let mut proc_macro_locator = locator.clone();
723
724            // Load the proc macro crate for the host
725            proc_macro_locator.for_proc_macro(sess, path_kind);
726
727            let Some(host_result) =
728                self.load(&mut proc_macro_locator, &mut CrateRejections::default())?
729            else {
730                return Ok(None);
731            };
732
733            Ok(Some((host_result, None)))
734        }
735    }
736
737    fn resolve_crate<'tcx>(
738        &mut self,
739        tcx: TyCtxt<'tcx>,
740        name: Symbol,
741        span: Span,
742        dep_kind: CrateDepKind,
743        origin: CrateOrigin<'_>,
744    ) -> Option<CrateNum> {
745        self.used_extern_options.insert(name);
746        match self.maybe_resolve_crate(tcx, name, dep_kind, origin) {
747            Ok(cnum) => {
748                self.set_used_recursively(cnum);
749                Some(cnum)
750            }
751            Err(err) => {
752                debug!("failed to resolve crate {} {:?}", name, dep_kind);
753                let missing_core = self
754                    .maybe_resolve_crate(
755                        tcx,
756                        sym::core,
757                        CrateDepKind::Explicit,
758                        CrateOrigin::Extern,
759                    )
760                    .is_err();
761                err.report(tcx.sess, span, missing_core);
762                None
763            }
764        }
765    }
766
767    fn maybe_resolve_crate<'b, 'tcx>(
768        &'b mut self,
769        tcx: TyCtxt<'tcx>,
770        name: Symbol,
771        mut dep_kind: CrateDepKind,
772        origin: CrateOrigin<'b>,
773    ) -> Result<CrateNum, CrateError> {
774        info!("resolving crate `{}`", name);
775        if !name.as_str().is_ascii() {
776            return Err(CrateError::NonAsciiName(name));
777        }
778
779        let dep_root = origin.dep_root();
780        let dep = origin.dep();
781        let hash = dep.map(|d| d.hash);
782        let host_hash = dep.map(|d| d.host_hash).flatten();
783        let extra_filename = dep.map(|d| &d.extra_filename[..]);
784        let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
785        let private_dep = origin.private_dep();
786
787        let result = if let Some(cnum) =
788            self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind)
789        {
790            (LoadResult::Previous(cnum), None)
791        } else {
792            info!("falling back to a load");
793            let mut locator = CrateLocator::new(
794                tcx.sess,
795                &*self.metadata_loader,
796                name,
797                // The all loop is because `--crate-type=rlib --crate-type=rlib` is
798                // legal and produces both inside this type.
799                tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
800                hash,
801                extra_filename,
802                path_kind,
803            );
804            let mut crate_rejections = CrateRejections::default();
805
806            match self.load(&mut locator, &mut crate_rejections)? {
807                Some(res) => (res, None),
808                None => {
809                    info!("falling back to loading proc_macro");
810                    dep_kind = CrateDepKind::MacrosOnly;
811                    match self.load_proc_macro(
812                        tcx.sess,
813                        &mut locator,
814                        &mut crate_rejections,
815                        path_kind,
816                        host_hash,
817                    )? {
818                        Some(res) => res,
819                        None => return Err(locator.into_error(crate_rejections, dep_root.cloned())),
820                    }
821                }
822            }
823        };
824
825        match result {
826            (LoadResult::Previous(cnum), None) => {
827                info!("library for `{}` was loaded previously, cnum {cnum}", name);
828                // When `private_dep` is none, it indicates the directly dependent crate. If it is
829                // not specified by `--extern` on command line parameters, it may be
830                // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to
831                // `public-dependency` here.
832                let private_dep =
833                    self.is_private_dep(&tcx.sess.opts.externs, name, private_dep, origin);
834                let data = self.get_crate_data_mut(cnum);
835                if data.is_proc_macro_crate() {
836                    dep_kind = CrateDepKind::MacrosOnly;
837                }
838                data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
839                data.update_and_private_dep(private_dep);
840                Ok(cnum)
841            }
842            (LoadResult::Loaded(library), host_library) => {
843                info!("register newly loaded library for `{}`", name);
844                self.register_crate(tcx, host_library, origin, library, dep_kind, name, private_dep)
845            }
846            _ => panic!(),
847        }
848    }
849
850    fn load(
851        &self,
852        locator: &CrateLocator<'_>,
853        crate_rejections: &mut CrateRejections,
854    ) -> Result<Option<LoadResult>, CrateError> {
855        let Some(library) = locator.maybe_load_library_crate(crate_rejections)? else {
856            return Ok(None);
857        };
858
859        // In the case that we're loading a crate, but not matching
860        // against a hash, we could load a crate which has the same hash
861        // as an already loaded crate. If this is the case prevent
862        // duplicates by just using the first crate.
863        let root = library.metadata.get_root();
864        let mut result = LoadResult::Loaded(library);
865        for (cnum, data) in self.iter_crate_data() {
866            if data.name() == root.name() && root.hash() == data.hash() {
867                assert!(locator.hash.is_none());
868                info!("load success, going to previous cnum: {}", cnum);
869                result = LoadResult::Previous(cnum);
870                break;
871            }
872        }
873        Ok(Some(result))
874    }
875
876    /// Go through the crate metadata and load any crates that it references.
877    fn resolve_crate_deps(
878        &mut self,
879        tcx: TyCtxt<'_>,
880        dep_root: &CratePaths,
881        crate_root: &CrateRoot,
882        metadata: &MetadataBlob,
883        krate: CrateNum,
884        dep_kind: CrateDepKind,
885        parent_is_private: bool,
886    ) -> Result<CrateNumMap, CrateError> {
887        debug!(
888            "resolving deps of external crate `{}` with dep root `{}`",
889            crate_root.name(),
890            dep_root.name
891        );
892        if crate_root.is_proc_macro_crate() {
893            return Ok(CrateNumMap::new());
894        }
895
896        // The map from crate numbers in the crate we're resolving to local crate numbers.
897        // We map 0 and all other holes in the map to our parent crate. The "additional"
898        // self-dependencies should be harmless.
899        let deps = crate_root.decode_crate_deps(metadata);
900        let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
901        crate_num_map.push(krate);
902        for dep in deps {
903            info!(
904                "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",
905                crate_root.name(),
906                dep.name,
907                dep.hash,
908                dep.extra_filename,
909                dep.is_private,
910            );
911            let dep_kind = match dep_kind {
912                CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
913                _ => dep.kind,
914            };
915            let cnum = self.maybe_resolve_crate(
916                tcx,
917                dep.name,
918                dep_kind,
919                CrateOrigin::IndirectDependency {
920                    dep_root,
921                    parent_private: parent_is_private,
922                    dep: &dep,
923                },
924            )?;
925            crate_num_map.push(cnum);
926        }
927
928        debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);
929        Ok(crate_num_map)
930    }
931
932    fn dlsym_proc_macros(
933        &self,
934        sess: &Session,
935        path: &Path,
936        stable_crate_id: StableCrateId,
937    ) -> Result<&'static [ProcMacro], CrateError> {
938        let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id);
939        debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
940
941        unsafe {
942            let result = load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name);
943            match result {
944                Ok(result) => {
945                    debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
946                    Ok(*result)
947                }
948                Err(err) => {
949                    debug!(
950                        "failed to dlsym proc_macros {} for symbol `{}`",
951                        path.display(),
952                        sym_name
953                    );
954                    Err(err.into())
955                }
956            }
957        }
958    }
959
960    fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
961        // If we're only compiling an rlib, then there's no need to select a
962        // panic runtime, so we just skip this section entirely.
963        let only_rlib = tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
964        if only_rlib {
965            info!("panic runtime injection skipped, only generating rlib");
966            return;
967        }
968
969        // If we need a panic runtime, we try to find an existing one here. At
970        // the same time we perform some general validation of the DAG we've got
971        // going such as ensuring everything has a compatible panic strategy.
972        let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
973        for (_cnum, data) in self.iter_crate_data() {
974            needs_panic_runtime |= data.needs_panic_runtime();
975        }
976
977        // If we just don't need a panic runtime at all, then we're done here
978        // and there's nothing else to do.
979        if !needs_panic_runtime {
980            return;
981        }
982
983        // By this point we know that we need a panic runtime. Here we just load
984        // an appropriate default runtime for our panic strategy.
985        //
986        // We may resolve to an already loaded crate (as the crate may not have
987        // been explicitly linked prior to this), but this is fine.
988        //
989        // Also note that we have yet to perform validation of the crate graph
990        // in terms of everyone has a compatible panic runtime format, that's
991        // performed later as part of the `dependency_format` module.
992        let desired_strategy = tcx.sess.panic_strategy();
993        let name = match desired_strategy {
994            PanicStrategy::Unwind => sym::panic_unwind,
995            PanicStrategy::Abort => sym::panic_abort,
996        };
997        info!("panic runtime not found -- loading {}", name);
998
999        let Some(cnum) =
1000            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
1001        else {
1002            return;
1003        };
1004        let data = self.get_crate_data(cnum);
1005
1006        // Sanity check the loaded crate to ensure it is indeed a panic runtime
1007        // and the panic strategy is indeed what we thought it was.
1008        if !data.is_panic_runtime() {
1009            tcx.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
1010        }
1011        if data.required_panic_strategy() != Some(desired_strategy) {
1012            tcx.dcx()
1013                .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
1014        }
1015
1016        self.injected_panic_runtime = Some(cnum);
1017    }
1018
1019    fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {
1020        let needs_profiler_runtime =
1021            tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled();
1022        if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime {
1023            return;
1024        }
1025
1026        info!("loading profiler");
1027
1028        let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);
1029        let Some(cnum) =
1030            self.resolve_crate(tcx, name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
1031        else {
1032            return;
1033        };
1034        let data = self.get_crate_data(cnum);
1035
1036        // Sanity check the loaded crate to ensure it is indeed a profiler runtime
1037        if !data.is_profiler_runtime() {
1038            tcx.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
1039        }
1040    }
1041
1042    fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
1043        self.has_global_allocator =
1044            match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {
1045                [span1, span2, ..] => {
1046                    tcx.dcx()
1047                        .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
1048                    true
1049                }
1050                spans => !spans.is_empty(),
1051            };
1052        self.has_alloc_error_handler = match &*fn_spans(
1053            krate,
1054            Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
1055        ) {
1056            [span1, span2, ..] => {
1057                tcx.dcx()
1058                    .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
1059                true
1060            }
1061            spans => !spans.is_empty(),
1062        };
1063
1064        // Check to see if we actually need an allocator. This desire comes
1065        // about through the `#![needs_allocator]` attribute and is typically
1066        // written down in liballoc.
1067        if !attr::contains_name(&krate.attrs, sym::needs_allocator)
1068            && !self.iter_crate_data().any(|(_, data)| data.needs_allocator())
1069        {
1070            return;
1071        }
1072
1073        // At this point we've determined that we need an allocator. Let's see
1074        // if our compilation session actually needs an allocator based on what
1075        // we're emitting.
1076        let all_rlib = tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
1077        if all_rlib {
1078            return;
1079        }
1080
1081        // Ok, we need an allocator. Not only that but we're actually going to
1082        // create an artifact that needs one linked in. Let's go find the one
1083        // that we're going to link in.
1084        //
1085        // First up we check for global allocators. Look at the crate graph here
1086        // and see what's a global allocator, including if we ourselves are a
1087        // global allocator.
1088        #[allow(rustc::symbol_intern_string_literal)]
1089        let this_crate = Symbol::intern("this crate");
1090
1091        let mut global_allocator = self.has_global_allocator.then_some(this_crate);
1092        for (_, data) in self.iter_crate_data() {
1093            if data.has_global_allocator() {
1094                match global_allocator {
1095                    Some(other_crate) => {
1096                        tcx.dcx().emit_err(errors::ConflictingGlobalAlloc {
1097                            crate_name: data.name(),
1098                            other_crate_name: other_crate,
1099                        });
1100                    }
1101                    None => global_allocator = Some(data.name()),
1102                }
1103            }
1104        }
1105        let mut alloc_error_handler = self.has_alloc_error_handler.then_some(this_crate);
1106        for (_, data) in self.iter_crate_data() {
1107            if data.has_alloc_error_handler() {
1108                match alloc_error_handler {
1109                    Some(other_crate) => {
1110                        tcx.dcx().emit_err(errors::ConflictingAllocErrorHandler {
1111                            crate_name: data.name(),
1112                            other_crate_name: other_crate,
1113                        });
1114                    }
1115                    None => alloc_error_handler = Some(data.name()),
1116                }
1117            }
1118        }
1119
1120        if global_allocator.is_some() {
1121            self.allocator_kind = Some(AllocatorKind::Global);
1122        } else {
1123            // Ok we haven't found a global allocator but we still need an
1124            // allocator. At this point our allocator request is typically fulfilled
1125            // by the standard library, denoted by the `#![default_lib_allocator]`
1126            // attribute.
1127            if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
1128                && !self.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
1129            {
1130                tcx.dcx().emit_err(errors::GlobalAllocRequired);
1131            }
1132            self.allocator_kind = Some(AllocatorKind::Default);
1133        }
1134
1135        if alloc_error_handler.is_some() {
1136            self.alloc_error_handler_kind = Some(AllocatorKind::Global);
1137        } else {
1138            // The alloc crate provides a default allocation error handler if
1139            // one isn't specified.
1140            self.alloc_error_handler_kind = Some(AllocatorKind::Default);
1141        }
1142    }
1143
1144    fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) {
1145        for (name, entry) in tcx.sess.opts.externs.iter() {
1146            if entry.force {
1147                let name_interned = Symbol::intern(name);
1148                if !self.used_extern_options.contains(&name_interned) {
1149                    self.resolve_crate(
1150                        tcx,
1151                        name_interned,
1152                        DUMMY_SP,
1153                        CrateDepKind::Explicit,
1154                        CrateOrigin::Extern,
1155                    );
1156                }
1157            }
1158        }
1159    }
1160
1161    /// Inject the `compiler_builtins` crate if it is not already in the graph.
1162    fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
1163        // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates
1164        if attr::contains_name(&krate.attrs, sym::compiler_builtins)
1165            || attr::contains_name(&krate.attrs, sym::no_core)
1166        {
1167            info!("`compiler_builtins` unneeded");
1168            return;
1169        }
1170
1171        // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is
1172        // the common case since usually it appears as a dependency of `std` or `alloc`.
1173        for (cnum, cmeta) in self.iter_crate_data() {
1174            if cmeta.is_compiler_builtins() {
1175                info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
1176                return;
1177            }
1178        }
1179
1180        // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.
1181        let Some(cnum) = self.resolve_crate(
1182            tcx,
1183            sym::compiler_builtins,
1184            krate.spans.inner_span.shrink_to_lo(),
1185            CrateDepKind::Explicit,
1186            CrateOrigin::Injected,
1187        ) else {
1188            info!("`compiler_builtins` not resolved");
1189            return;
1190        };
1191
1192        // Sanity check that the loaded crate is `#![compiler_builtins]`
1193        let cmeta = self.get_crate_data(cnum);
1194        if !cmeta.is_compiler_builtins() {
1195            tcx.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
1196        }
1197    }
1198
1199    fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
1200        // Make a point span rather than covering the whole file
1201        let span = krate.spans.inner_span.shrink_to_lo();
1202        // Complain about anything left over
1203        for (name, entry) in tcx.sess.opts.externs.iter() {
1204            if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
1205                // Don't worry about pathless `--extern foo` sysroot references
1206                continue;
1207            }
1208            if entry.nounused_dep || entry.force {
1209                // We're not worried about this one
1210                continue;
1211            }
1212            let name_interned = Symbol::intern(name);
1213            if self.used_extern_options.contains(&name_interned) {
1214                continue;
1215            }
1216
1217            // Got a real unused --extern
1218            if tcx.sess.opts.json_unused_externs.is_enabled() {
1219                self.unused_externs.push(name_interned);
1220                continue;
1221            }
1222
1223            tcx.sess.psess.buffer_lint(
1224                lint::builtin::UNUSED_CRATE_DEPENDENCIES,
1225                span,
1226                ast::CRATE_NODE_ID,
1227                BuiltinLintDiag::UnusedCrateDependency {
1228                    extern_crate: name_interned,
1229                    local_crate: tcx.crate_name(LOCAL_CRATE),
1230                },
1231            );
1232        }
1233    }
1234
1235    fn report_future_incompatible_deps(&self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
1236        let name = tcx.crate_name(LOCAL_CRATE);
1237
1238        if name.as_str() == "wasm_bindgen" {
1239            let major = env::var("CARGO_PKG_VERSION_MAJOR")
1240                .ok()
1241                .and_then(|major| u64::from_str(&major).ok());
1242            let minor = env::var("CARGO_PKG_VERSION_MINOR")
1243                .ok()
1244                .and_then(|minor| u64::from_str(&minor).ok());
1245            let patch = env::var("CARGO_PKG_VERSION_PATCH")
1246                .ok()
1247                .and_then(|patch| u64::from_str(&patch).ok());
1248
1249            match (major, minor, patch) {
1250                // v1 or bigger is valid.
1251                (Some(1..), _, _) => return,
1252                // v0.3 or bigger is valid.
1253                (Some(0), Some(3..), _) => return,
1254                // v0.2.88 or bigger is valid.
1255                (Some(0), Some(2), Some(88..)) => return,
1256                // Not using Cargo.
1257                (None, None, None) => return,
1258                _ => (),
1259            }
1260
1261            // Make a point span rather than covering the whole file
1262            let span = krate.spans.inner_span.shrink_to_lo();
1263
1264            tcx.sess.dcx().emit_err(errors::WasmCAbi { span });
1265        }
1266    }
1267
1268    pub fn postprocess(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {
1269        self.inject_compiler_builtins(tcx, krate);
1270        self.inject_forced_externs(tcx);
1271        self.inject_profiler_runtime(tcx);
1272        self.inject_allocator_crate(tcx, krate);
1273        self.inject_panic_runtime(tcx, krate);
1274
1275        self.report_unused_deps_in_crate(tcx, krate);
1276        self.report_future_incompatible_deps(tcx, krate);
1277
1278        info!("{:?}", CrateDump(self));
1279    }
1280
1281    /// Process an `extern crate foo` AST node.
1282    pub fn process_extern_crate(
1283        &mut self,
1284        tcx: TyCtxt<'_>,
1285        item: &ast::Item,
1286        def_id: LocalDefId,
1287        definitions: &Definitions,
1288    ) -> Option<CrateNum> {
1289        match item.kind {
1290            ast::ItemKind::ExternCrate(orig_name, ident) => {
1291                debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);
1292                let name = match orig_name {
1293                    Some(orig_name) => {
1294                        validate_crate_name(tcx.sess, orig_name, Some(item.span));
1295                        orig_name
1296                    }
1297                    None => ident.name,
1298                };
1299                let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
1300                    CrateDepKind::MacrosOnly
1301                } else {
1302                    CrateDepKind::Explicit
1303                };
1304
1305                let cnum =
1306                    self.resolve_crate(tcx, name, item.span, dep_kind, CrateOrigin::Extern)?;
1307
1308                let path_len = definitions.def_path(def_id).data.len();
1309                self.update_extern_crate(
1310                    cnum,
1311                    ExternCrate {
1312                        src: ExternCrateSource::Extern(def_id.to_def_id()),
1313                        span: item.span,
1314                        path_len,
1315                        dependency_of: LOCAL_CRATE,
1316                    },
1317                );
1318                Some(cnum)
1319            }
1320            _ => bug!(),
1321        }
1322    }
1323
1324    pub fn process_path_extern(
1325        &mut self,
1326        tcx: TyCtxt<'_>,
1327        name: Symbol,
1328        span: Span,
1329    ) -> Option<CrateNum> {
1330        let cnum =
1331            self.resolve_crate(tcx, name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
1332
1333        self.update_extern_crate(
1334            cnum,
1335            ExternCrate {
1336                src: ExternCrateSource::Path,
1337                span,
1338                // to have the least priority in `update_extern_crate`
1339                path_len: usize::MAX,
1340                dependency_of: LOCAL_CRATE,
1341            },
1342        );
1343
1344        Some(cnum)
1345    }
1346
1347    pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option<CrateNum> {
1348        self.maybe_resolve_crate(tcx, name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
1349    }
1350}
1351
1352fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec<Span> {
1353    struct Finder {
1354        name: Symbol,
1355        spans: Vec<Span>,
1356    }
1357    impl<'ast> visit::Visitor<'ast> for Finder {
1358        fn visit_item(&mut self, item: &'ast ast::Item) {
1359            if let Some(ident) = item.kind.ident()
1360                && ident.name == self.name
1361                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1362            {
1363                self.spans.push(item.span);
1364            }
1365            visit::walk_item(self, item)
1366        }
1367    }
1368
1369    let mut f = Finder { name, spans: Vec::new() };
1370    visit::walk_crate(&mut f, krate);
1371    f.spans
1372}
1373
1374fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
1375    e.sources().map(|e| format!(": {e}")).collect()
1376}
1377
1378fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
1379    #[cfg(target_os = "aix")]
1380    if let Some(ext) = path.extension()
1381        && ext.eq("a")
1382    {
1383        // On AIX, we ship all libraries as .a big_af archive
1384        // the expected format is lib<name>.a(libname.so) for the actual
1385        // dynamic library
1386        let library_name = path.file_stem().expect("expect a library name");
1387        let mut archive_member = std::ffi::OsString::from("a(");
1388        archive_member.push(library_name);
1389        archive_member.push(".so)");
1390        let new_path = path.with_extension(archive_member);
1391
1392        // On AIX, we need RTLD_MEMBER to dlopen an archived shared
1393        let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
1394        return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
1395            .map(|lib| lib.into());
1396    }
1397
1398    unsafe { libloading::Library::new(&path) }
1399}
1400
1401// On Windows the compiler would sometimes intermittently fail to open the
1402// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
1403// system still holds a lock on the file, so we retry a few times before calling it
1404// an error.
1405fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
1406    assert!(max_attempts > 0);
1407
1408    let mut last_error = None;
1409
1410    for attempt in 0..max_attempts {
1411        debug!("Attempt to load proc-macro `{}`.", path.display());
1412        match attempt_load_dylib(path) {
1413            Ok(lib) => {
1414                if attempt > 0 {
1415                    debug!(
1416                        "Loaded proc-macro `{}` after {} attempts.",
1417                        path.display(),
1418                        attempt + 1
1419                    );
1420                }
1421                return Ok(lib);
1422            }
1423            Err(err) => {
1424                // Only try to recover from this specific error.
1425                if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
1426                    debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
1427                    let err = format_dlopen_err(&err);
1428                    // We include the path of the dylib in the error ourselves, so
1429                    // if it's in the error, we strip it.
1430                    if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) {
1431                        return Err(err.to_string());
1432                    }
1433                    return Err(err);
1434                }
1435
1436                last_error = Some(err);
1437                std::thread::sleep(Duration::from_millis(100));
1438                debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
1439            }
1440        }
1441    }
1442
1443    debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
1444
1445    let last_error = last_error.unwrap();
1446    let message = if let Some(src) = last_error.source() {
1447        format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
1448    } else {
1449        format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
1450    };
1451    Err(message)
1452}
1453
1454pub enum DylibError {
1455    DlOpen(String, String),
1456    DlSym(String, String),
1457}
1458
1459impl From<DylibError> for CrateError {
1460    fn from(err: DylibError) -> CrateError {
1461        match err {
1462            DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
1463            DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
1464        }
1465    }
1466}
1467
1468pub unsafe fn load_symbol_from_dylib<T: Copy>(
1469    path: &Path,
1470    sym_name: &str,
1471) -> Result<T, DylibError> {
1472    // Make sure the path contains a / or the linker will search for it.
1473    let path = try_canonicalize(path).unwrap();
1474    let lib =
1475        load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
1476
1477    let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
1478        .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
1479
1480    // Intentionally leak the dynamic library. We can't ever unload it
1481    // since the library can make things that will live arbitrarily long.
1482    let sym = unsafe { sym.into_raw() };
1483    std::mem::forget(lib);
1484
1485    Ok(*sym)
1486}