compiler/rustc_metadata/src/creader.rs RUST 1,532 lines View on github.com → Search inside
1//! Validates all used crates and extern libraries and loads their metadata23use std::collections::BTreeMap;4use std::error::Error;5use std::path::Path;6use std::str::FromStr;7use std::time::Duration;8use std::{cmp, env, iter};910use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, AllocatorKind, global_fn_name};11use rustc_ast::{self as ast, *};12use rustc_data_structures::fx::FxHashSet;13use rustc_data_structures::owned_slice::OwnedSlice;14use rustc_data_structures::svh::Svh;15use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};16use rustc_data_structures::unord::UnordMap;17use rustc_expand::base::SyntaxExtension;18use rustc_fs_util::try_canonicalize;19use rustc_hir as hir;20use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId};21use rustc_hir::definitions::Definitions;22use rustc_index::IndexVec;23use rustc_middle::bug;24use rustc_middle::ty::data_structures::IndexSet;25use rustc_middle::ty::{TyCtxt, TyCtxtFeed};26use rustc_proc_macro::bridge::client::Client as ProcMacroClient;27use rustc_session::config::mitigation_coverage::DeniedPartialMitigationLevel;28use rustc_session::config::{29    CrateType, ExtendedTargetModifierInfo, ExternLocation, Externs, OptionsTargetModifiers,30    TargetModifier,31};32use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};33use rustc_session::output::validate_crate_name;34use rustc_session::search_paths::PathKind;35use rustc_session::{Session, lint};36use rustc_span::def_id::DefId;37use rustc_span::edition::Edition;38use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};39use rustc_target::spec::{PanicStrategy, Target};40use tracing::{debug, info, trace};4142use crate::diagnostics;43use crate::locator::{CrateError, CrateLocator, CratePaths, CrateRejections};44use crate::rmeta::{45    CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,46};4748/// The backend's way to give the crate store access to the metadata in a library.49/// Note that it returns the raw metadata bytes stored in the library file, whether50/// it is compressed, uncompressed, some weird mix, etc.51/// rmeta files are backend independent and not handled here.52pub trait MetadataLoader {53    fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;54    fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;55}5657pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;5859pub struct CStore {60    metadata_loader: Box<MetadataLoaderDyn>,6162    metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>,63    injected_panic_runtime: Option<CrateNum>,64    /// This crate needs an allocator 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    allocator_kind: Option<AllocatorKind>,67    /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.68    /// If the above is true, then this field denotes the kind of the found allocator.69    alloc_error_handler_kind: Option<AllocatorKind>,70    /// This crate has a `#[global_allocator]` item.71    has_global_allocator: bool,72    /// This crate has a `#[alloc_error_handler]` item.73    has_alloc_error_handler: bool,7475    /// Names that were used to load the crates via `extern crate` or paths.76    resolved_externs: UnordMap<Symbol, CrateNum>,7778    /// Unused externs of the crate79    unused_externs: Vec<Symbol>,8081    used_extern_options: FxHashSet<Symbol>,82    /// Whether there was a failure in resolving crate,83    /// it's used to suppress some diagnostics that would otherwise too noisey.84    has_crate_resolve_with_fail: bool,85}8687impl std::fmt::Debug for CStore {88    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {89        f.debug_struct("CStore").finish_non_exhaustive()90    }91}9293pub enum LoadedMacro {94    MacroDef {95        def: MacroDef,96        ident: Ident,97        attrs: Vec<hir::Attribute>,98        span: Span,99        edition: Edition,100    },101    ProcMacro(SyntaxExtension),102}103104pub(crate) struct Library {105    pub source: CrateSource,106    pub metadata: MetadataBlob,107}108109enum LoadResult {110    Previous(CrateNum),111    Loaded(Library),112}113114struct CrateDump<'a>(&'a CStore);115116impl<'a> std::fmt::Debug for CrateDump<'a> {117    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {118        writeln!(fmt, "resolved crates:")?;119        for (cnum, data) in self.0.iter_crate_data() {120            writeln!(fmt, "  name: {}", data.name())?;121            writeln!(fmt, "  cnum: {cnum}")?;122            writeln!(fmt, "  hash: {}", data.hash())?;123            writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;124            writeln!(fmt, "  priv: {:?}", data.is_private_dep())?;125            let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();126            if let Some(dylib) = dylib {127                writeln!(fmt, "  dylib: {}", dylib.display())?;128            }129            if let Some(rlib) = rlib {130                writeln!(fmt, "   rlib: {}", rlib.display())?;131            }132            if let Some(rmeta) = rmeta {133                writeln!(fmt, "   rmeta: {}", rmeta.display())?;134            }135            if let Some(sdylib_interface) = sdylib_interface {136                writeln!(fmt, "   sdylib interface: {}", sdylib_interface.display())?;137            }138        }139        Ok(())140    }141}142143/// Reason that a crate is being sourced as a dependency.144#[derive(Clone, Copy)]145enum CrateOrigin<'a> {146    /// This crate was a dependency of another crate.147    IndirectDependency {148        /// Where this dependency was included from. Should only be used in error messages.149        dep_root_for_errors: &'a CratePaths,150        /// True if the parent is private, meaning the dependent should also be private.151        parent_private: bool,152        /// Dependency info about this crate.153        dep: &'a CrateDep,154    },155    /// Injected by `rustc`.156    Injected,157    /// Provided by `extern crate foo` or as part of the extern prelude.158    Extern,159}160161impl<'a> CrateOrigin<'a> {162    /// Return the dependency root, if any.163    fn dep_root_for_errors(&self) -> Option<&'a CratePaths> {164        match self {165            CrateOrigin::IndirectDependency { dep_root_for_errors, .. } => {166                Some(dep_root_for_errors)167            }168            _ => None,169        }170    }171172    /// Return dependency information, if any.173    fn dep(&self) -> Option<&'a CrateDep> {174        match self {175            CrateOrigin::IndirectDependency { dep, .. } => Some(dep),176            _ => None,177        }178    }179180    /// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the181    /// dependency is not private, `None` if it could not be determined.182    fn private_dep(&self) -> Option<bool> {183        match self {184            CrateOrigin::IndirectDependency { parent_private, dep, .. } => {185                Some(dep.is_private || *parent_private)186            }187            CrateOrigin::Injected => Some(true),188            _ => None,189        }190    }191}192193impl CStore {194    pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {195        FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {196            cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")197        })198    }199200    pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {201        FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {202            cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")203        })204    }205206    fn intern_stable_crate_id<'tcx>(207        &mut self,208        tcx: TyCtxt<'tcx>,209        root: &CrateRoot,210    ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {211        assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());212        let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {213            // Check for (potential) conflicts with the local crate214            if existing == LOCAL_CRATE {215                CrateError::SymbolConflictsCurrent(root.name())216            } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())217            {218                let crate_name0 = root.name();219                CrateError::StableCrateIdCollision(crate_name0, crate_name1)220            } else {221                CrateError::NotFound(root.name())222            }223        })?;224225        self.metas.push(None);226        Ok(num)227    }228229    pub fn has_crate_data(&self, cnum: CrateNum) -> bool {230        self.metas[cnum].is_some()231    }232233    pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> &CrateMetadata {234        self.metas[cnum].as_ref().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))235    }236237    pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {238        self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))239    }240241    fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {242        assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");243        self.metas[cnum] = Some(Box::new(data));244    }245246    /// Save the name used to resolve the extern crate in the local crate247    ///248    /// The name isn't always the crate's own name, because `sess.opts.externs` can assign it another name.249    /// It's also not always the same as the `DefId`'s symbol due to renames `extern crate resolved_name as defid_name`.250    pub(crate) fn set_resolved_extern_crate_name(&mut self, name: Symbol, extern_crate: CrateNum) {251        self.resolved_externs.insert(name, extern_crate);252    }253254    /// Crate resolved and loaded via the given extern name255    /// (corresponds to names in `sess.opts.externs`)256    ///257    /// May be `None` if the crate wasn't used258    pub fn resolved_extern_crate(&self, externs_name: Symbol) -> Option<CrateNum> {259        self.resolved_externs.get(&externs_name).copied()260    }261262    pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {263        self.metas264            .iter_enumerated()265            .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))266    }267268    pub fn all_proc_macro_def_ids(&self, tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> {269        self.iter_crate_data().flat_map(move |(krate, data)| data.proc_macros_for_crate(tcx, krate))270    }271272    fn push_dependencies_in_postorder(&self, deps: &mut IndexSet<CrateNum>, cnum: CrateNum) {273        if !deps.contains(&cnum) {274            let cdata = self.get_crate_data(cnum);275            for dep in cdata.dependencies() {276                if dep != cnum {277                    self.push_dependencies_in_postorder(deps, dep);278                }279            }280281            deps.insert(cnum);282        }283    }284285    pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> IndexSet<CrateNum> {286        let mut deps = IndexSet::default();287        if cnum == LOCAL_CRATE {288            for (cnum, _) in self.iter_crate_data() {289                self.push_dependencies_in_postorder(&mut deps, cnum);290            }291        } else {292            self.push_dependencies_in_postorder(&mut deps, cnum);293        }294        deps295    }296297    pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {298        self.injected_panic_runtime299    }300301    pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {302        self.allocator_kind303    }304305    pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {306        self.alloc_error_handler_kind307    }308309    pub(crate) fn has_global_allocator(&self) -> bool {310        self.has_global_allocator311    }312313    pub(crate) fn has_alloc_error_handler(&self) -> bool {314        self.has_alloc_error_handler315    }316317    pub fn had_extern_crate_load_failure(&self) -> bool {318        self.has_crate_resolve_with_fail319    }320321    pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {322        let json_unused_externs = tcx.sess.opts.json_unused_externs;323324        // We put the check for the option before the lint_level_at_node call325        // because the call mutates internal state and introducing it326        // leads to some ui tests failing.327        if !json_unused_externs.is_enabled() {328            return;329        }330        let level = tcx331            .lint_level_spec_at_node(332                lint::builtin::UNUSED_CRATE_DEPENDENCIES,333                rustc_hir::CRATE_HIR_ID,334            )335            .level();336        if level != lint::Level::Allow {337            let unused_externs =338                self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();339            let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();340            tcx.dcx().emit_unused_externs(level, json_unused_externs.is_loud(), &unused_externs);341        }342    }343344    fn report_target_modifiers_extended(345        tcx: TyCtxt<'_>,346        krate: &Crate,347        mods: &TargetModifiers,348        dep_mods: &TargetModifiers,349        data: &CrateMetadata,350    ) {351        let span = krate.spans.inner_span.shrink_to_lo();352        let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;353        let local_crate = tcx.crate_name(LOCAL_CRATE);354        let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());355        let report_diff = |prefix: &String,356                           opt_name: &String,357                           flag_local_value: Option<&String>,358                           flag_extern_value: Option<&String>| {359            if allowed_flag_mismatches.contains(&opt_name) {360                return;361            }362            let extern_crate = data.name();363            let flag_name = opt_name.clone();364            let flag_name_prefixed = format!("-{}{}", prefix, opt_name);365366            match (flag_local_value, flag_extern_value) {367                (Some(local_value), Some(extern_value)) => {368                    tcx.dcx().emit_err(diagnostics::IncompatibleTargetModifiers {369                        span,370                        extern_crate,371                        local_crate,372                        flag_name,373                        flag_name_prefixed,374                        local_value: local_value.to_string(),375                        extern_value: extern_value.to_string(),376                    })377                }378                (None, Some(extern_value)) => {379                    tcx.dcx().emit_err(diagnostics::IncompatibleTargetModifiersLMissed {380                        span,381                        extern_crate,382                        local_crate,383                        flag_name,384                        flag_name_prefixed,385                        extern_value: extern_value.to_string(),386                    })387                }388                (Some(local_value), None) => {389                    tcx.dcx().emit_err(diagnostics::IncompatibleTargetModifiersRMissed {390                        span,391                        extern_crate,392                        local_crate,393                        flag_name,394                        flag_name_prefixed,395                        local_value: local_value.to_string(),396                    })397                }398                (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),399            };400        };401        let mut it1 = mods.iter().map(tmod_extender);402        let mut it2 = dep_mods.iter().map(tmod_extender);403        let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;404        let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;405        loop {406            left_name_val = left_name_val.or_else(|| it1.next());407            right_name_val = right_name_val.or_else(|| it2.next());408            match (&left_name_val, &right_name_val) {409                (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {410                    cmp::Ordering::Equal => {411                        if !l.1.consistent(&tcx.sess, Some(&r.1)) {412                            report_diff(413                                &l.0.prefix,414                                &l.0.name,415                                Some(&l.1.value_name),416                                Some(&r.1.value_name),417                            );418                        }419                        left_name_val = None;420                        right_name_val = None;421                    }422                    cmp::Ordering::Greater => {423                        if !r.1.consistent(&tcx.sess, None) {424                            report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));425                        }426                        right_name_val = None;427                    }428                    cmp::Ordering::Less => {429                        if !l.1.consistent(&tcx.sess, None) {430                            report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);431                        }432                        left_name_val = None;433                    }434                },435                (Some(l), None) => {436                    if !l.1.consistent(&tcx.sess, None) {437                        report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);438                    }439                    left_name_val = None;440                }441                (None, Some(r)) => {442                    if !r.1.consistent(&tcx.sess, None) {443                        report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));444                    }445                    right_name_val = None;446                }447                (None, None) => break,448            }449        }450    }451452    pub fn report_session_incompatibilities(&self, tcx: TyCtxt<'_>, krate: &Crate) {453        self.report_incompatible_target_modifiers(tcx, krate);454        self.report_incompatible_partial_mitigations(tcx, krate);455        self.report_incompatible_async_drop_feature(tcx, krate);456    }457458    pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {459        for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {460            if !OptionsTargetModifiers::is_target_modifier(flag_name) {461                tcx.dcx().emit_err(diagnostics::UnknownTargetModifierUnsafeAllowed {462                    span: krate.spans.inner_span.shrink_to_lo(),463                    flag_name: flag_name.clone(),464                });465            }466        }467        let mods = tcx.sess.opts.gather_target_modifiers();468        for (_cnum, data) in self.iter_crate_data() {469            if data.is_proc_macro_crate() {470                continue;471            }472            let dep_mods = data.target_modifiers();473            if mods != dep_mods {474                Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);475            }476        }477    }478479    pub fn report_incompatible_partial_mitigations(&self, tcx: TyCtxt<'_>, krate: &Crate) {480        let my_mitigations = tcx.sess.gather_enabled_denied_partial_mitigations();481        let mut my_mitigations: BTreeMap<_, _> =482            my_mitigations.iter().map(|mitigation| (mitigation.kind, mitigation)).collect();483        for skipped_mitigation in tcx.sess.opts.allowed_partial_mitigations(tcx.sess.edition()) {484            my_mitigations.remove(&skipped_mitigation);485        }486        const MAX_ERRORS_PER_MITIGATION: usize = 5;487        let mut errors_per_mitigation = BTreeMap::new();488        for (_cnum, data) in self.iter_crate_data() {489            if data.is_proc_macro_crate() {490                continue;491            }492            let their_mitigations = data.enabled_denied_partial_mitigations();493            for my_mitigation in my_mitigations.values() {494                let their_mitigation = their_mitigations495                    .iter()496                    .find(|mitigation| mitigation.kind == my_mitigation.kind)497                    .map_or(DeniedPartialMitigationLevel::Enabled(false), |m| m.level);498                if their_mitigation < my_mitigation.level {499                    let errors = errors_per_mitigation.entry(my_mitigation.kind).or_insert(0);500                    if *errors >= MAX_ERRORS_PER_MITIGATION {501                        continue;502                    }503                    *errors += 1;504505                    tcx.dcx().emit_err(diagnostics::MitigationLessStrictInDependency {506                        span: krate.spans.inner_span.shrink_to_lo(),507                        mitigation_name: my_mitigation.kind.to_string(),508                        mitigation_level: my_mitigation.level.level_str().to_string(),509                        extern_crate: data.name(),510                    });511                }512            }513        }514    }515516    // Report about async drop types in dependency if async drop feature is disabled517    pub fn report_incompatible_async_drop_feature(&self, tcx: TyCtxt<'_>, krate: &Crate) {518        if tcx.features().async_drop() {519            return;520        }521        for (_cnum, data) in self.iter_crate_data() {522            if data.is_proc_macro_crate() {523                continue;524            }525            if data.has_async_drops() {526                let extern_crate = data.name();527                let local_crate = tcx.crate_name(LOCAL_CRATE);528                tcx.dcx().emit_warn(diagnostics::AsyncDropTypesInDependency {529                    span: krate.spans.inner_span.shrink_to_lo(),530                    extern_crate,531                    local_crate,532                });533            }534        }535    }536537    pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {538        CStore {539            metadata_loader,540            // We add an empty entry for LOCAL_CRATE (which maps to zero) in541            // order to make array indices in `metas` match with the542            // corresponding `CrateNum`. This first entry will always remain543            // `None`.544            metas: IndexVec::from_iter(iter::once(None)),545            injected_panic_runtime: None,546            allocator_kind: None,547            alloc_error_handler_kind: None,548            has_global_allocator: false,549            has_alloc_error_handler: false,550            resolved_externs: UnordMap::default(),551            unused_externs: Vec::new(),552            used_extern_options: Default::default(),553            has_crate_resolve_with_fail: false,554        }555    }556557    fn existing_match(&self, name: Symbol, hash: Option<Svh>) -> Option<CrateNum> {558        let hash = hash?;559560        for (cnum, data) in self.iter_crate_data() {561            if data.name() != name {562                trace!("{} did not match {}", data.name(), name);563                continue;564            }565566            if hash == data.hash() {567                return Some(cnum);568            } else {569                debug!("actual hash {} did not match expected {}", hash, data.hash());570            }571        }572573        None574    }575576    /// Determine whether a dependency should be considered private.577    ///578    /// Dependencies are private if they get extern option specified, e.g. `--extern priv:mycrate`.579    /// This is stored in metadata, so `private_dep`  can be correctly set during load. A `Some`580    /// value for `private_dep` indicates that the crate is known to be private or public (note581    /// that any `None` or `Some(false)` use of the same crate will make it public).582    ///583    /// Sometimes the directly dependent crate is not specified by `--extern`, in this case,584    /// `private-dep` is none during loading. This is equivalent to the scenario where the585    /// command parameter is set to `public-dependency`586    fn is_private_dep(&self, externs: &Externs, name: Symbol, private_dep: Option<bool>) -> bool {587        let extern_private = externs.get(name.as_str()).map(|e| e.is_private_dep);588        match (extern_private, private_dep) {589            // Explicit non-private via `--extern`, explicit non-private from metadata, or590            // unspecified with default to public.591            (Some(false), _) | (_, Some(false)) | (None, None) => false,592            // Marked private via `--extern priv:mycrate` or in metadata.593            (Some(true) | None, Some(true) | None) => true,594        }595    }596597    fn register_crate<'tcx>(598        &mut self,599        tcx: TyCtxt<'tcx>,600        host_lib: Option<Library>,601        origin: CrateOrigin<'_>,602        lib: Library,603        dep_kind: CrateDepKind,604        name: Symbol,605        private_dep: Option<bool>,606    ) -> Result<CrateNum, CrateError> {607        let _prof_timer =608            tcx.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());609610        let Library { source, metadata } = lib;611        let crate_root = metadata.get_root();612        let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());613        let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep);614615        // Claim this crate number and cache it616        let feed = self.intern_stable_crate_id(tcx, &crate_root)?;617        let cnum = feed.key();618619        info!(620            "register crate `{}` (cnum = {}. private_dep = {})",621            crate_root.name(),622            cnum,623            private_dep624        );625626        // Maintain a reference to the top most crate.627        // Stash paths for top-most crate locally if necessary.628        let crate_paths;629        let dep_root_for_errors = if let Some(dep_root_for_errors) = origin.dep_root_for_errors() {630            dep_root_for_errors631        } else {632            crate_paths = CratePaths::new(crate_root.name(), source.clone());633            &crate_paths634        };635636        let cnum_map = self.resolve_crate_deps(637            tcx,638            dep_root_for_errors,639            &crate_root,640            &metadata,641            cnum,642            dep_kind,643            private_dep,644        )?;645646        let raw_proc_macros = if crate_root.is_proc_macro_crate() {647            let temp_root;648            let (dlsym_source, dlsym_root) = match &host_lib {649                Some(host_lib) => (&host_lib.source, {650                    temp_root = host_lib.metadata.get_root();651                    &temp_root652                }),653                None => (&source, &crate_root),654            };655            let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");656            Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?)657        } else {658            None659        };660661        let crate_metadata = CrateMetadata::new(662            tcx,663            metadata,664            crate_root,665            raw_proc_macros,666            cnum,667            cnum_map,668            dep_kind,669            source,670            private_dep,671            host_hash,672        );673674        self.set_crate_data(cnum, crate_metadata);675676        Ok(cnum)677    }678679    fn load_proc_macro<'a, 'b>(680        &self,681        sess: &'a Session,682        locator: &mut CrateLocator<'b>,683        crate_rejections: &mut CrateRejections,684        path_kind: PathKind,685        host_hash: Option<Svh>,686    ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>687    where688        'a: 'b,689    {690        if sess.opts.unstable_opts.dual_proc_macros {691            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't692            // affect the error message we emit693            let mut proc_macro_locator = locator.clone();694695            // Try to load a proc macro696            proc_macro_locator.for_target_proc_macro(sess, path_kind);697698            // Load the proc macro crate for the target699            let target_result =700                match self.load(&mut proc_macro_locator, &mut CrateRejections::default())? {701                    Some(LoadResult::Previous(cnum)) => {702                        return Ok(Some((LoadResult::Previous(cnum), None)));703                    }704                    Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),705                    None => return Ok(None),706                };707708            // Use the existing crate_rejections as we want the error message to be affected by709            // loading the host proc macro.710            *crate_rejections = CrateRejections::default();711712            // Load the proc macro crate for the host713            locator.for_proc_macro(sess, path_kind);714715            locator.hash = host_hash;716717            let Some(host_result) = self.load(locator, crate_rejections)? else {718                return Ok(None);719            };720721            let host_result = match host_result {722                LoadResult::Previous(..) => {723                    panic!("host and target proc macros must be loaded in lock-step")724                }725                LoadResult::Loaded(library) => library,726            };727            Ok(Some((target_result.unwrap(), Some(host_result))))728        } else {729            // Use a new crate locator and crate rejections so trying to load a proc macro doesn't730            // affect the error message we emit731            let mut proc_macro_locator = locator.clone();732733            // Load the proc macro crate for the host734            proc_macro_locator.for_proc_macro(sess, path_kind);735736            let Some(host_result) =737                self.load(&mut proc_macro_locator, &mut CrateRejections::default())?738            else {739                return Ok(None);740            };741742            Ok(Some((host_result, None)))743        }744    }745746    fn resolve_crate<'tcx>(747        &mut self,748        tcx: TyCtxt<'tcx>,749        name: Symbol,750        span: Span,751        dep_kind: CrateDepKind,752        origin: CrateOrigin<'_>,753    ) -> Option<CrateNum> {754        self.used_extern_options.insert(name);755        match self.maybe_resolve_crate(tcx, name, dep_kind, origin) {756            Ok(cnum) => {757                self.set_used_recursively(cnum);758                Some(cnum)759            }760            Err(err) => {761                debug!("failed to resolve crate {} {:?}", name, dep_kind);762                // crate maybe injrected with `standard_library_imports::inject`, their span is dummy.763                // we ignore compiler-injected prelude/sysroot loads here so they don't suppress764                // unrelated diagnostics, such as `unsupported targets for std library` etc,765                // these maybe helpful for users to resolve crate loading failure.766                if !tcx.sess.dcx().has_errors().is_some() && !span.is_dummy() {767                    self.has_crate_resolve_with_fail = true;768                }769                let missing_core = self770                    .maybe_resolve_crate(771                        tcx,772                        sym::core,773                        CrateDepKind::Unconditional,774                        CrateOrigin::Extern,775                    )776                    .is_err();777                err.report(tcx.sess, span, missing_core);778                None779            }780        }781    }782783    fn maybe_resolve_crate<'b, 'tcx>(784        &'b mut self,785        tcx: TyCtxt<'tcx>,786        name: Symbol,787        mut dep_kind: CrateDepKind,788        origin: CrateOrigin<'b>,789    ) -> Result<CrateNum, CrateError> {790        info!("resolving crate `{}`", name);791        if !name.as_str().is_ascii() {792            return Err(CrateError::NonAsciiName(name));793        }794795        let dep_root_for_errors = origin.dep_root_for_errors();796        let dep = origin.dep();797        let hash = dep.map(|d| d.hash);798        let host_hash = dep.map(|d| d.host_hash).flatten();799        let extra_filename = dep.map(|d| &d.extra_filename[..]);800        let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };801        let private_dep = origin.private_dep();802803        let result = if let Some(cnum) = self.existing_match(name, hash) {804            (LoadResult::Previous(cnum), None)805        } else {806            info!("falling back to a load");807            let mut locator = CrateLocator::new(808                tcx.sess,809                &*self.metadata_loader,810                name,811                // The all loop is because `--crate-type=rlib --crate-type=rlib` is812                // legal and produces both inside this type.813                tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),814                hash,815                extra_filename,816                path_kind,817            );818            let mut crate_rejections = CrateRejections::default();819820            match self.load(&mut locator, &mut crate_rejections)? {821                Some(res) => (res, None),822                None => {823                    info!("falling back to loading proc_macro");824                    dep_kind = CrateDepKind::MacrosOnly;825                    match self.load_proc_macro(826                        tcx.sess,827                        &mut locator,828                        &mut crate_rejections,829                        path_kind,830                        host_hash,831                    )? {832                        Some(res) => res,833                        None => {834                            return Err(835                                locator.into_error(crate_rejections, dep_root_for_errors.cloned())836                            );837                        }838                    }839                }840            }841        };842843        match result {844            (LoadResult::Previous(cnum), None) => {845                info!("library for `{}` was loaded previously, cnum {cnum}", name);846                // When `private_dep` is none, it indicates the directly dependent crate. If it is847                // not specified by `--extern` on command line parameters, it may be848                // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to849                // `public-dependency` here.850                let private_dep = self.is_private_dep(&tcx.sess.opts.externs, name, private_dep);851                let cdata = self.get_crate_data_mut(cnum);852                if cdata.is_proc_macro_crate() {853                    dep_kind = CrateDepKind::MacrosOnly;854                }855                cdata.set_dep_kind(cmp::max(cdata.dep_kind(), dep_kind));856                cdata.update_and_private_dep(private_dep);857                Ok(cnum)858            }859            (LoadResult::Loaded(library), host_library) => {860                info!("register newly loaded library for `{}`", name);861                self.register_crate(tcx, host_library, origin, library, dep_kind, name, private_dep)862            }863            _ => panic!(),864        }865    }866867    fn load(868        &self,869        locator: &CrateLocator<'_>,870        crate_rejections: &mut CrateRejections,871    ) -> Result<Option<LoadResult>, CrateError> {872        let Some(library) = locator.maybe_load_library_crate(crate_rejections)? else {873            return Ok(None);874        };875876        // In the case that we're loading a crate, but not matching877        // against a hash, we could load a crate which has the same hash878        // as an already loaded crate. If this is the case prevent879        // duplicates by just using the first crate.880        let root = library.metadata.get_root();881        let mut result = LoadResult::Loaded(library);882        for (cnum, data) in self.iter_crate_data() {883            if data.name() == root.name() && root.hash() == data.hash() {884                assert!(locator.hash.is_none());885                info!("load success, going to previous cnum: {}", cnum);886                result = LoadResult::Previous(cnum);887                break;888            }889        }890        Ok(Some(result))891    }892893    /// Go through the crate metadata and load any crates that it references.894    fn resolve_crate_deps(895        &mut self,896        tcx: TyCtxt<'_>,897        dep_root_for_errors: &CratePaths,898        crate_root: &CrateRoot,899        metadata: &MetadataBlob,900        krate: CrateNum,901        dep_kind: CrateDepKind,902        parent_is_private: bool,903    ) -> Result<CrateNumMap, CrateError> {904        debug!(905            "resolving deps of external crate `{}` with dep root `{}`",906            crate_root.name(),907            dep_root_for_errors.name908        );909        if crate_root.is_proc_macro_crate() {910            return Ok(CrateNumMap::new());911        }912913        // The map from crate numbers in the crate we're resolving to local crate numbers.914        // We map 0 and all other holes in the map to our parent crate. The "additional"915        // self-dependencies should be harmless.916        let deps = crate_root.decode_crate_deps(metadata);917        let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());918        crate_num_map.push(krate);919        for dep in deps {920            info!(921                "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",922                crate_root.name(),923                dep.name,924                dep.hash,925                dep.extra_filename,926                dep.is_private,927            );928            let dep_kind = match dep_kind {929                CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,930                _ => dep.kind,931            };932            let cnum = self.maybe_resolve_crate(933                tcx,934                dep.name,935                dep_kind,936                CrateOrigin::IndirectDependency {937                    dep_root_for_errors,938                    parent_private: parent_is_private,939                    dep: &dep,940                },941            )?;942            crate_num_map.push(cnum);943        }944945        debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);946        Ok(crate_num_map)947    }948949    fn dlsym_proc_macros(950        &self,951        sess: &Session,952        path: &Path,953        stable_crate_id: StableCrateId,954    ) -> Result<&'static [ProcMacroClient], CrateError> {955        let sym_name = sess.generate_proc_macro_decls_symbol(stable_crate_id);956        debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);957958        unsafe {959            // FIXME(bjorn3) this depends on the unstable slice memory layout960            let result = load_symbol_from_dylib::<*const &[ProcMacroClient]>(path, &sym_name);961            match result {962                Ok(result) => {963                    debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);964                    Ok(*result)965                }966                Err(err) => {967                    debug!(968                        "failed to dlsym proc_macros {} for symbol `{}`",969                        path.display(),970                        sym_name971                    );972                    Err(err.into())973                }974            }975        }976    }977978    fn inject_panic_runtime(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {979        // If we're only compiling an rlib, then there's no need to select a980        // panic runtime, so we just skip this section entirely.981        let only_rlib = tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);982        if only_rlib {983            info!("panic runtime injection skipped, only generating rlib");984            return;985        }986987        // If we need a panic runtime, we try to find an existing one here. At988        // the same time we perform some general validation of the DAG we've got989        // going such as ensuring everything has a compatible panic strategy.990        let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);991        for (_cnum, data) in self.iter_crate_data() {992            needs_panic_runtime |= data.needs_panic_runtime();993        }994995        // If we just don't need a panic runtime at all, then we're done here996        // and there's nothing else to do.997        if !needs_panic_runtime {998            return;999        }10001001        // By this point we know that we need a panic runtime. Here we just load1002        // an appropriate default runtime for our panic strategy.1003        //1004        // We may resolve to an already loaded crate (as the crate may not have1005        // been explicitly linked prior to this), but this is fine.1006        //1007        // Also note that we have yet to perform validation of the crate graph1008        // in terms of everyone has a compatible panic runtime format, that's1009        // performed later as part of the `dependency_format` module.1010        let desired_strategy = tcx.sess.panic_strategy();1011        let name = match desired_strategy {1012            PanicStrategy::Unwind => sym::panic_unwind,1013            PanicStrategy::Abort => sym::panic_abort,1014            PanicStrategy::ImmediateAbort => {1015                // Immediate-aborting panics don't use a runtime.1016                return;1017            }1018        };1019        info!("panic runtime not found -- loading {}", name);10201021        // This has to be conditional as both panic_unwind and panic_abort may be present in the1022        // crate graph at the same time. One of them will later be activated in dependency_formats.1023        let Some(cnum) = self.resolve_crate(1024            tcx,1025            name,1026            DUMMY_SP,1027            CrateDepKind::Conditional,1028            CrateOrigin::Injected,1029        ) else {1030            return;1031        };1032        let cdata = self.get_crate_data(cnum);10331034        // Sanity check the loaded crate to ensure it is indeed a panic runtime1035        // and the panic strategy is indeed what we thought it was.1036        if !cdata.is_panic_runtime() {1037            tcx.dcx().emit_err(diagnostics::CrateNotPanicRuntime { crate_name: name });1038        }1039        if cdata.required_panic_strategy() != Some(desired_strategy) {1040            tcx.dcx().emit_err(diagnostics::NoPanicStrategy {1041                crate_name: name,1042                strategy: desired_strategy,1043            });1044        }10451046        self.injected_panic_runtime = Some(cnum);1047    }10481049    fn inject_profiler_runtime(&mut self, tcx: TyCtxt<'_>) {1050        let needs_profiler_runtime =1051            tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled();1052        if !needs_profiler_runtime || tcx.sess.opts.unstable_opts.no_profiler_runtime {1053            return;1054        }10551056        info!("loading profiler");10571058        // HACK: This uses conditional despite actually being unconditional to ensure that1059        // there is no error emitted when two dylibs independently depend on profiler_builtins.1060        // This is fine as profiler_builtins is always statically linked into the dylib just1061        // like compiler_builtins. Unlike compiler_builtins however there is no guaranteed1062        // common dylib that the duplicate crate check believes the crate to be included in.1063        // add_upstream_rust_crates has a corresponding check that forces profiler_builtins1064        // to be statically linked in even when marked as NotLinked.1065        let name = Symbol::intern(&tcx.sess.opts.unstable_opts.profiler_runtime);1066        let Some(cnum) = self.resolve_crate(1067            tcx,1068            name,1069            DUMMY_SP,1070            CrateDepKind::Conditional,1071            CrateOrigin::Injected,1072        ) else {1073            return;1074        };1075        let cdata = self.get_crate_data(cnum);10761077        // Sanity check the loaded crate to ensure it is indeed a profiler runtime1078        if !cdata.is_profiler_runtime() {1079            tcx.dcx().emit_err(diagnostics::NotProfilerRuntime { crate_name: name });1080        }1081    }10821083    fn inject_allocator_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {1084        self.has_global_allocator =1085            match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {1086                [span1, span2, ..] => {1087                    tcx.dcx().emit_err(diagnostics::NoMultipleGlobalAlloc {1088                        span2: *span2,1089                        span1: *span1,1090                    });1091                    true1092                }1093                spans => !spans.is_empty(),1094            };1095        let alloc_error_handler = Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER));1096        self.has_alloc_error_handler = match &*fn_spans(krate, alloc_error_handler) {1097            [span1, span2, ..] => {1098                tcx.dcx().emit_err(diagnostics::NoMultipleAllocErrorHandler {1099                    span2: *span2,1100                    span1: *span1,1101                });1102                true1103            }1104            spans => !spans.is_empty(),1105        };11061107        // Check to see if we actually need an allocator. This desire comes1108        // about through the `#![needs_allocator]` attribute and is typically1109        // written down in liballoc.1110        if !attr::contains_name(&krate.attrs, sym::needs_allocator)1111            && !self.iter_crate_data().any(|(_, data)| data.needs_allocator())1112        {1113            return;1114        }11151116        // At this point we've determined that we need an allocator. Let's see1117        // if our compilation session actually needs an allocator based on what1118        // we're emitting.1119        let all_rlib = tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));1120        if all_rlib {1121            return;1122        }11231124        // Ok, we need an allocator. Not only that but we're actually going to1125        // create an artifact that needs one linked in. Let's go find the one1126        // that we're going to link in.1127        //1128        // First up we check for global allocators. Look at the crate graph here1129        // and see what's a global allocator, including if we ourselves are a1130        // global allocator.1131        #[allow(rustc::symbol_intern_string_literal)]1132        let this_crate = Symbol::intern("this crate");11331134        let mut global_allocator = self.has_global_allocator.then_some(this_crate);1135        for (_, data) in self.iter_crate_data() {1136            if data.has_global_allocator() {1137                match global_allocator {1138                    Some(other_crate) => {1139                        tcx.dcx().emit_err(diagnostics::ConflictingGlobalAlloc {1140                            crate_name: data.name(),1141                            other_crate_name: other_crate,1142                        });1143                    }1144                    None => global_allocator = Some(data.name()),1145                }1146            }1147        }1148        let mut alloc_error_handler = self.has_alloc_error_handler.then_some(this_crate);1149        for (_, data) in self.iter_crate_data() {1150            if data.has_alloc_error_handler() {1151                match alloc_error_handler {1152                    Some(other_crate) => {1153                        tcx.dcx().emit_err(diagnostics::ConflictingAllocErrorHandler {1154                            crate_name: data.name(),1155                            other_crate_name: other_crate,1156                        });1157                    }1158                    None => alloc_error_handler = Some(data.name()),1159                }1160            }1161        }11621163        if global_allocator.is_some() {1164            self.allocator_kind = Some(AllocatorKind::Global);1165        } else {1166            // Ok we haven't found a global allocator but we still need an1167            // allocator. At this point our allocator request is typically fulfilled1168            // by the standard library, denoted by the `#![default_lib_allocator]`1169            // attribute.1170            if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)1171                && !self.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())1172            {1173                tcx.dcx().emit_err(diagnostics::GlobalAllocRequired);1174            }1175            self.allocator_kind = Some(AllocatorKind::Default);1176        }11771178        if alloc_error_handler.is_some() {1179            self.alloc_error_handler_kind = Some(AllocatorKind::Global);1180        } else {1181            // The alloc crate provides a default allocation error handler if1182            // one isn't specified.1183            self.alloc_error_handler_kind = Some(AllocatorKind::Default);1184        }1185    }11861187    fn inject_forced_externs(&mut self, tcx: TyCtxt<'_>) {1188        for (name, entry) in tcx.sess.opts.externs.iter() {1189            if entry.force {1190                let name_interned = Symbol::intern(name);1191                if !self.used_extern_options.contains(&name_interned) {1192                    self.resolve_crate(1193                        tcx,1194                        name_interned,1195                        DUMMY_SP,1196                        CrateDepKind::Unconditional,1197                        CrateOrigin::Extern,1198                    );1199                }1200            }1201        }1202    }12031204    /// Inject the `compiler_builtins` crate if it is not already in the graph.1205    fn inject_compiler_builtins(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {1206        // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates1207        if attr::contains_name(&krate.attrs, sym::compiler_builtins)1208            || attr::contains_name(&krate.attrs, sym::no_core)1209        {1210            info!("`compiler_builtins` unneeded");1211            return;1212        }12131214        // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is1215        // the common case since usually it appears as a dependency of `std` or `alloc`.1216        for (cnum, cmeta) in self.iter_crate_data() {1217            if cmeta.is_compiler_builtins() {1218                info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");1219                return;1220            }1221        }12221223        // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure.1224        let Some(cnum) = self.resolve_crate(1225            tcx,1226            sym::compiler_builtins,1227            krate.spans.inner_span.shrink_to_lo(),1228            CrateDepKind::Unconditional,1229            CrateOrigin::Injected,1230        ) else {1231            info!("`compiler_builtins` not resolved");1232            return;1233        };12341235        // Sanity check that the loaded crate is `#![compiler_builtins]`1236        let cdata = self.get_crate_data(cnum);1237        if !cdata.is_compiler_builtins() {1238            tcx.dcx().emit_err(diagnostics::CrateNotCompilerBuiltins { crate_name: cdata.name() });1239        }1240    }12411242    fn report_unused_deps_in_crate(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {1243        // Make a point span rather than covering the whole file1244        let span = krate.spans.inner_span.shrink_to_lo();1245        // Complain about anything left over1246        for (name, entry) in tcx.sess.opts.externs.iter() {1247            if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {1248                // Don't worry about pathless `--extern foo` sysroot references1249                continue;1250            }1251            if entry.nounused_dep || entry.force {1252                // We're not worried about this one1253                continue;1254            }1255            let name_interned = Symbol::intern(name);1256            if self.used_extern_options.contains(&name_interned) {1257                continue;1258            }12591260            // Got a real unused --extern1261            if tcx.sess.opts.json_unused_externs.is_enabled() {1262                self.unused_externs.push(name_interned);1263                continue;1264            }12651266            tcx.sess.psess.buffer_lint(1267                lint::builtin::UNUSED_CRATE_DEPENDENCIES,1268                span,1269                ast::CRATE_NODE_ID,1270                diagnostics::UnusedCrateDependency {1271                    extern_crate: name_interned,1272                    local_crate: tcx.crate_name(LOCAL_CRATE),1273                },1274            );1275        }1276    }12771278    fn report_future_incompatible_deps(&self, tcx: TyCtxt<'_>, krate: &ast::Crate) {1279        let name = tcx.crate_name(LOCAL_CRATE);12801281        if name.as_str() == "wasm_bindgen" {1282            let major = env::var("CARGO_PKG_VERSION_MAJOR")1283                .ok()1284                .and_then(|major| u64::from_str(&major).ok());1285            let minor = env::var("CARGO_PKG_VERSION_MINOR")1286                .ok()1287                .and_then(|minor| u64::from_str(&minor).ok());1288            let patch = env::var("CARGO_PKG_VERSION_PATCH")1289                .ok()1290                .and_then(|patch| u64::from_str(&patch).ok());12911292            match (major, minor, patch) {1293                // v1 or bigger is valid.1294                (Some(1..), _, _) => return,1295                // v0.3 or bigger is valid.1296                (Some(0), Some(3..), _) => return,1297                // v0.2.88 or bigger is valid.1298                (Some(0), Some(2), Some(88..)) => return,1299                // Not using Cargo.1300                (None, None, None) => return,1301                _ => (),1302            }13031304            // Make a point span rather than covering the whole file1305            let span = krate.spans.inner_span.shrink_to_lo();13061307            tcx.sess.dcx().emit_err(diagnostics::WasmCAbi { span });1308        }1309    }13101311    pub fn postprocess(&mut self, tcx: TyCtxt<'_>, krate: &ast::Crate) {1312        self.inject_compiler_builtins(tcx, krate);1313        self.inject_forced_externs(tcx);1314        self.inject_profiler_runtime(tcx);1315        self.inject_allocator_crate(tcx, krate);1316        self.inject_panic_runtime(tcx, krate);13171318        self.report_unused_deps_in_crate(tcx, krate);1319        self.report_future_incompatible_deps(tcx, krate);13201321        info!("{:?}", CrateDump(self));1322    }13231324    /// Process an `extern crate foo` AST node.1325    pub fn process_extern_crate(1326        &mut self,1327        tcx: TyCtxt<'_>,1328        item: &ast::Item,1329        def_id: LocalDefId,1330        definitions: &Definitions,1331    ) -> Option<CrateNum> {1332        match item.kind {1333            ast::ItemKind::ExternCrate(orig_name, ident) => {1334                debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);1335                let name = match orig_name {1336                    Some(orig_name) => {1337                        validate_crate_name(tcx.sess, orig_name, Some(item.span));1338                        orig_name1339                    }1340                    None => ident.name,1341                };1342                let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {1343                    CrateDepKind::MacrosOnly1344                } else {1345                    CrateDepKind::Unconditional1346                };13471348                let cnum =1349                    self.resolve_crate(tcx, name, item.span, dep_kind, CrateOrigin::Extern)?;13501351                let path_len = definitions.def_path(def_id).data.len();1352                self.update_extern_crate(1353                    cnum,1354                    name,1355                    ExternCrate {1356                        src: ExternCrateSource::Extern(def_id.to_def_id()),1357                        span: item.span,1358                        path_len,1359                        dependency_of: LOCAL_CRATE,1360                    },1361                );1362                Some(cnum)1363            }1364            _ => bug!(),1365        }1366    }13671368    pub fn process_path_extern(1369        &mut self,1370        tcx: TyCtxt<'_>,1371        name: Symbol,1372        span: Span,1373    ) -> Option<CrateNum> {1374        let cnum =1375            self.resolve_crate(tcx, name, span, CrateDepKind::Unconditional, CrateOrigin::Extern)?;13761377        self.update_extern_crate(1378            cnum,1379            name,1380            ExternCrate {1381                src: ExternCrateSource::Path,1382                span,1383                // to have the least priority in `update_extern_crate`1384                path_len: usize::MAX,1385                dependency_of: LOCAL_CRATE,1386            },1387        );13881389        Some(cnum)1390    }13911392    pub fn maybe_process_path_extern(&mut self, tcx: TyCtxt<'_>, name: Symbol) -> Option<CrateNum> {1393        self.maybe_resolve_crate(tcx, name, CrateDepKind::Unconditional, CrateOrigin::Extern).ok()1394    }1395}13961397fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec<Span> {1398    struct Finder {1399        name: Symbol,1400        spans: Vec<Span>,1401    }1402    impl<'ast> visit::Visitor<'ast> for Finder {1403        fn visit_item(&mut self, item: &'ast ast::Item) {1404            if let Some(ident) = item.kind.ident()1405                && ident.name == self.name1406                && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)1407            {1408                self.spans.push(item.span);1409            }1410            visit::walk_item(self, item)1411        }1412    }14131414    let mut f = Finder { name, spans: Vec::new() };1415    visit::walk_crate(&mut f, krate);1416    f.spans1417}14181419fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {1420    e.sources().map(|e| format!(": {e}")).collect()1421}14221423fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {1424    #[cfg(target_os = "aix")]1425    if let Some(ext) = path.extension()1426        && ext.eq("a")1427    {1428        // On AIX, we ship all libraries as .a big_af archive1429        // the expected format is lib<name>.a(libname.so) for the actual1430        // dynamic library1431        let library_name = path.file_stem().expect("expect a library name");1432        let mut archive_member = std::ffi::OsString::from("a(");1433        archive_member.push(library_name);1434        archive_member.push(".so)");1435        let new_path = path.with_extension(archive_member);14361437        // On AIX, we need RTLD_MEMBER to dlopen an archived shared1438        let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;1439        return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }1440            .map(|lib| lib.into());1441    }14421443    unsafe { libloading::Library::new(&path) }1444}14451446// On Windows the compiler would sometimes intermittently fail to open the1447// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the1448// system still holds a lock on the file, so we retry a few times before calling it1449// an error.1450fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {1451    assert!(max_attempts > 0);14521453    let mut last_error = None;14541455    for attempt in 0..max_attempts {1456        debug!("Attempt to load proc-macro `{}`.", path.display());1457        match attempt_load_dylib(path) {1458            Ok(lib) => {1459                if attempt > 0 {1460                    debug!(1461                        "Loaded proc-macro `{}` after {} attempts.",1462                        path.display(),1463                        attempt + 11464                    );1465                }1466                return Ok(lib);1467            }1468            Err(err) => {1469                // Only try to recover from this specific error.1470                if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {1471                    debug!("Failed to load proc-macro `{}`. Not retrying", path.display());1472                    let err = format_dlopen_err(&err);1473                    // We include the path of the dylib in the error ourselves, so1474                    // if it's in the error, we strip it.1475                    if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) {1476                        return Err(err.to_string());1477                    }1478                    return Err(err);1479                }14801481                last_error = Some(err);1482                std::thread::sleep(Duration::from_millis(100));1483                debug!("Failed to load proc-macro `{}`. Retrying.", path.display());1484            }1485        }1486    }14871488    debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);14891490    let last_error = last_error.unwrap();1491    let message = if let Some(src) = last_error.source() {1492        format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))1493    } else {1494        format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))1495    };1496    Err(message)1497}14981499pub enum DylibError {1500    DlOpen(String, String),1501    DlSym(String, String),1502}15031504impl From<DylibError> for CrateError {1505    fn from(err: DylibError) -> CrateError {1506        match err {1507            DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),1508            DylibError::DlSym(path, err) => CrateError::DlSym(path, err),1509        }1510    }1511}15121513pub unsafe fn load_symbol_from_dylib<T: Copy>(1514    path: &Path,1515    sym_name: &str,1516) -> Result<T, DylibError> {1517    // Make sure the path contains a / or the linker will search for it.1518    let path = try_canonicalize(path).unwrap();1519    let lib =1520        load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;15211522    let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }1523        .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;15241525    // Intentionally leak the dynamic library. We can't ever unload it1526    // since the library can make things that will live arbitrarily long.1527    let sym = unsafe { sym.into_raw() };1528    std::mem::forget(lib);15291530    Ok(*sym)1531}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.