rustc_metadata/
creader.rs

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