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.