1use std::error::Error;
4use std::ops::Fn;
5use std::path::Path;
6use std::str::FromStr;
7use std::time::Duration;
8use std::{cmp, env, iter};
9
10use proc_macro::bridge::client::ProcMacro;
11use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name};
12use rustc_ast::{self as ast, *};
13use rustc_data_structures::fx::FxHashSet;
14use rustc_data_structures::owned_slice::OwnedSlice;
15use rustc_data_structures::svh::Svh;
16use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
17use rustc_errors::DiagCtxtHandle;
18use rustc_expand::base::SyntaxExtension;
19use rustc_fs_util::try_canonicalize;
20use rustc_hir as hir;
21use rustc_hir::def_id::{CrateNum, LOCAL_CRATE, LocalDefId, StableCrateId};
22use rustc_hir::definitions::Definitions;
23use rustc_index::IndexVec;
24use rustc_middle::bug;
25use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
26use rustc_session::config::{
27 self, CrateType, ExtendedTargetModifierInfo, ExternLocation, OptionsTargetModifiers,
28 TargetModifier,
29};
30use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
31use rustc_session::lint::{self, BuiltinLintDiag};
32use rustc_session::output::validate_crate_name;
33use rustc_session::search_paths::PathKind;
34use rustc_span::edition::Edition;
35use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
36use rustc_target::spec::{PanicStrategy, Target, TargetTuple};
37use tracing::{debug, info, trace};
38
39use crate::errors;
40use crate::locator::{CrateError, CrateLocator, CratePaths};
41use crate::rmeta::{
42 CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob, TargetModifiers,
43};
44
45pub trait MetadataLoader {
50 fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
51 fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
52}
53
54pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
55
56pub struct CStore {
57 metadata_loader: Box<MetadataLoaderDyn>,
58
59 metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>,
60 injected_panic_runtime: Option<CrateNum>,
61 allocator_kind: Option<AllocatorKind>,
64 alloc_error_handler_kind: Option<AllocatorKind>,
67 has_global_allocator: bool,
69 has_alloc_error_handler: bool,
71
72 unused_externs: Vec<Symbol>,
74}
75
76impl std::fmt::Debug for CStore {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("CStore").finish_non_exhaustive()
79 }
80}
81
82pub struct CrateLoader<'a, 'tcx: 'a> {
83 tcx: TyCtxt<'tcx>,
85 cstore: &'a mut CStore,
87 used_extern_options: &'a mut FxHashSet<Symbol>,
88}
89
90impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
91 type Target = TyCtxt<'tcx>;
92
93 fn deref(&self) -> &Self::Target {
94 &self.tcx
95 }
96}
97
98impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
99 fn dcx(&self) -> DiagCtxtHandle<'tcx> {
100 self.tcx.dcx()
101 }
102}
103
104pub enum LoadedMacro {
105 MacroDef {
106 def: MacroDef,
107 ident: Ident,
108 attrs: Vec<hir::Attribute>,
109 span: Span,
110 edition: Edition,
111 },
112 ProcMacro(SyntaxExtension),
113}
114
115pub(crate) struct Library {
116 pub source: CrateSource,
117 pub metadata: MetadataBlob,
118}
119
120enum LoadResult {
121 Previous(CrateNum),
122 Loaded(Library),
123}
124
125#[derive(Clone, Copy)]
127pub(crate) struct CrateMetadataRef<'a> {
128 pub cdata: &'a CrateMetadata,
129 pub cstore: &'a CStore,
130}
131
132impl std::ops::Deref for CrateMetadataRef<'_> {
133 type Target = CrateMetadata;
134
135 fn deref(&self) -> &Self::Target {
136 self.cdata
137 }
138}
139
140struct CrateDump<'a>(&'a CStore);
141
142impl<'a> std::fmt::Debug for CrateDump<'a> {
143 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 writeln!(fmt, "resolved crates:")?;
145 for (cnum, data) in self.0.iter_crate_data() {
146 writeln!(fmt, " name: {}", data.name())?;
147 writeln!(fmt, " cnum: {cnum}")?;
148 writeln!(fmt, " hash: {}", data.hash())?;
149 writeln!(fmt, " reqd: {:?}", data.dep_kind())?;
150 writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
151 let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
152 if let Some(dylib) = dylib {
153 writeln!(fmt, " dylib: {}", dylib.0.display())?;
154 }
155 if let Some(rlib) = rlib {
156 writeln!(fmt, " rlib: {}", rlib.0.display())?;
157 }
158 if let Some(rmeta) = rmeta {
159 writeln!(fmt, " rmeta: {}", rmeta.0.display())?;
160 }
161 if let Some(sdylib_interface) = sdylib_interface {
162 writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;
163 }
164 }
165 Ok(())
166 }
167}
168
169#[derive(Clone, Copy)]
171enum CrateOrigin<'a> {
172 IndirectDependency {
174 dep_root: &'a CratePaths,
176 parent_private: bool,
178 dep: &'a CrateDep,
180 },
181 Injected,
183 Extern,
185}
186
187impl<'a> CrateOrigin<'a> {
188 fn dep_root(&self) -> Option<&'a CratePaths> {
190 match self {
191 CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root),
192 _ => None,
193 }
194 }
195
196 fn dep(&self) -> Option<&'a CrateDep> {
198 match self {
199 CrateOrigin::IndirectDependency { dep, .. } => Some(dep),
200 _ => None,
201 }
202 }
203
204 fn private_dep(&self) -> Option<bool> {
207 match self {
208 CrateOrigin::IndirectDependency { parent_private, dep, .. } => {
209 Some(dep.is_private || *parent_private)
210 }
211 _ => None,
212 }
213 }
214}
215
216impl CStore {
217 pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> {
218 FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
219 cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
220 })
221 }
222
223 pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> FreezeWriteGuard<'_, CStore> {
224 FreezeWriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
225 cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
226 })
227 }
228
229 fn intern_stable_crate_id<'tcx>(
230 &mut self,
231 root: &CrateRoot,
232 tcx: TyCtxt<'tcx>,
233 ) -> Result<TyCtxtFeed<'tcx, CrateNum>, CrateError> {
234 assert_eq!(self.metas.len(), tcx.untracked().stable_crate_ids.read().len());
235 let num = tcx.create_crate_num(root.stable_crate_id()).map_err(|existing| {
236 if existing == LOCAL_CRATE {
238 CrateError::SymbolConflictsCurrent(root.name())
239 } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
240 {
241 let crate_name0 = root.name();
242 CrateError::StableCrateIdCollision(crate_name0, crate_name1)
243 } else {
244 CrateError::NotFound(root.name())
245 }
246 })?;
247
248 self.metas.push(None);
249 Ok(num)
250 }
251
252 pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
253 self.metas[cnum].is_some()
254 }
255
256 pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
257 let cdata = self.metas[cnum]
258 .as_ref()
259 .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
260 CrateMetadataRef { cdata, cstore: self }
261 }
262
263 pub(crate) fn get_crate_data_mut(&mut self, cnum: CrateNum) -> &mut CrateMetadata {
264 self.metas[cnum].as_mut().unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"))
265 }
266
267 fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
268 assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
269 self.metas[cnum] = Some(Box::new(data));
270 }
271
272 pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
273 self.metas
274 .iter_enumerated()
275 .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
276 }
277
278 fn iter_crate_data_mut(&mut self) -> impl Iterator<Item = (CrateNum, &mut CrateMetadata)> {
279 self.metas
280 .iter_enumerated_mut()
281 .filter_map(|(cnum, data)| data.as_deref_mut().map(|data| (cnum, data)))
282 }
283
284 fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
285 if !deps.contains(&cnum) {
286 let data = self.get_crate_data(cnum);
287 for dep in data.dependencies() {
288 if dep != cnum {
289 self.push_dependencies_in_postorder(deps, dep);
290 }
291 }
292
293 deps.push(cnum);
294 }
295 }
296
297 pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
298 let mut deps = Vec::new();
299 if cnum == LOCAL_CRATE {
300 for (cnum, _) in self.iter_crate_data() {
301 self.push_dependencies_in_postorder(&mut deps, cnum);
302 }
303 } else {
304 self.push_dependencies_in_postorder(&mut deps, cnum);
305 }
306 deps
307 }
308
309 fn crate_dependencies_in_reverse_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
310 let mut deps = self.crate_dependencies_in_postorder(cnum);
311 deps.reverse();
312 deps
313 }
314
315 pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
316 self.injected_panic_runtime
317 }
318
319 pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {
320 self.allocator_kind
321 }
322
323 pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
324 self.alloc_error_handler_kind
325 }
326
327 pub(crate) fn has_global_allocator(&self) -> bool {
328 self.has_global_allocator
329 }
330
331 pub(crate) fn has_alloc_error_handler(&self) -> bool {
332 self.has_alloc_error_handler
333 }
334
335 pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
336 let json_unused_externs = tcx.sess.opts.json_unused_externs;
337
338 if !json_unused_externs.is_enabled() {
342 return;
343 }
344 let level = tcx
345 .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
346 .level;
347 if level != lint::Level::Allow {
348 let unused_externs =
349 self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
350 let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
351 tcx.dcx().emit_unused_externs(level, json_unused_externs.is_loud(), &unused_externs);
352 }
353 }
354
355 fn report_target_modifiers_extended(
356 tcx: TyCtxt<'_>,
357 krate: &Crate,
358 mods: &TargetModifiers,
359 dep_mods: &TargetModifiers,
360 data: &CrateMetadata,
361 ) {
362 let span = krate.spans.inner_span.shrink_to_lo();
363 let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
364 let local_crate = tcx.crate_name(LOCAL_CRATE);
365 let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
366 let report_diff = |prefix: &String,
367 opt_name: &String,
368 flag_local_value: Option<&String>,
369 flag_extern_value: Option<&String>| {
370 if allowed_flag_mismatches.contains(&opt_name) {
371 return;
372 }
373 let extern_crate = data.name();
374 let flag_name = opt_name.clone();
375 let flag_name_prefixed = format!("-{}{}", prefix, opt_name);
376
377 match (flag_local_value, flag_extern_value) {
378 (Some(local_value), Some(extern_value)) => {
379 tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
380 span,
381 extern_crate,
382 local_crate,
383 flag_name,
384 flag_name_prefixed,
385 local_value: local_value.to_string(),
386 extern_value: extern_value.to_string(),
387 })
388 }
389 (None, Some(extern_value)) => {
390 tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed {
391 span,
392 extern_crate,
393 local_crate,
394 flag_name,
395 flag_name_prefixed,
396 extern_value: extern_value.to_string(),
397 })
398 }
399 (Some(local_value), None) => {
400 tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed {
401 span,
402 extern_crate,
403 local_crate,
404 flag_name,
405 flag_name_prefixed,
406 local_value: local_value.to_string(),
407 })
408 }
409 (None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),
410 };
411 };
412 let mut it1 = mods.iter().map(tmod_extender);
413 let mut it2 = dep_mods.iter().map(tmod_extender);
414 let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
415 let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
416 loop {
417 left_name_val = left_name_val.or_else(|| it1.next());
418 right_name_val = right_name_val.or_else(|| it2.next());
419 match (&left_name_val, &right_name_val) {
420 (Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
421 cmp::Ordering::Equal => {
422 if l.0.tech_value != r.0.tech_value {
423 report_diff(
424 &l.0.prefix,
425 &l.0.name,
426 Some(&l.1.value_name),
427 Some(&r.1.value_name),
428 );
429 }
430 left_name_val = None;
431 right_name_val = None;
432 }
433 cmp::Ordering::Greater => {
434 report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
435 right_name_val = None;
436 }
437 cmp::Ordering::Less => {
438 report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
439 left_name_val = None;
440 }
441 },
442 (Some(l), None) => {
443 report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
444 left_name_val = None;
445 }
446 (None, Some(r)) => {
447 report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
448 right_name_val = None;
449 }
450 (None, None) => break,
451 }
452 }
453 }
454
455 pub fn report_incompatible_target_modifiers(&self, tcx: TyCtxt<'_>, krate: &Crate) {
456 for flag_name in &tcx.sess.opts.cg.unsafe_allow_abi_mismatch {
457 if !OptionsTargetModifiers::is_target_modifier(flag_name) {
458 tcx.dcx().emit_err(errors::UnknownTargetModifierUnsafeAllowed {
459 span: krate.spans.inner_span.shrink_to_lo(),
460 flag_name: flag_name.clone(),
461 });
462 }
463 }
464 let mods = tcx.sess.opts.gather_target_modifiers();
465 for (_cnum, data) in self.iter_crate_data() {
466 if data.is_proc_macro_crate() {
467 continue;
468 }
469 let dep_mods = data.target_modifiers();
470 if mods != dep_mods {
471 Self::report_target_modifiers_extended(tcx, krate, &mods, &dep_mods, data);
472 }
473 }
474 }
475
476 pub fn new(metadata_loader: Box<MetadataLoaderDyn>) -> CStore {
477 CStore {
478 metadata_loader,
479 metas: IndexVec::from_iter(iter::once(None)),
484 injected_panic_runtime: None,
485 allocator_kind: None,
486 alloc_error_handler_kind: None,
487 has_global_allocator: false,
488 has_alloc_error_handler: false,
489 unused_externs: Vec::new(),
490 }
491 }
492}
493
494impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
495 pub fn new(
496 tcx: TyCtxt<'tcx>,
497 cstore: &'a mut CStore,
498 used_extern_options: &'a mut FxHashSet<Symbol>,
499 ) -> Self {
500 CrateLoader { tcx, cstore, used_extern_options }
501 }
502
503 fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
504 for (cnum, data) in self.cstore.iter_crate_data() {
505 if data.name() != name {
506 trace!("{} did not match {}", data.name(), name);
507 continue;
508 }
509
510 match hash {
511 Some(hash) if hash == data.hash() => return Some(cnum),
512 Some(hash) => {
513 debug!("actual hash {} did not match expected {}", hash, data.hash());
514 continue;
515 }
516 None => {}
517 }
518
519 let source = self.cstore.get_crate_data(cnum).cdata.source();
529 if let Some(entry) = self.sess.opts.externs.get(name.as_str()) {
530 if let Some(mut files) = entry.files() {
532 if files.any(|l| {
533 let l = l.canonicalized();
534 source.dylib.as_ref().map(|(p, _)| p) == Some(l)
535 || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
536 || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
537 }) {
538 return Some(cnum);
539 }
540 }
541 continue;
542 }
543
544 let prev_kind = source
551 .dylib
552 .as_ref()
553 .or(source.rlib.as_ref())
554 .or(source.rmeta.as_ref())
555 .expect("No sources for crate")
556 .1;
557 if kind.matches(prev_kind) {
558 return Some(cnum);
559 } else {
560 debug!(
561 "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
562 name, kind, prev_kind
563 );
564 }
565 }
566
567 None
568 }
569
570 fn is_private_dep(
581 &self,
582 name: Symbol,
583 private_dep: Option<bool>,
584 origin: CrateOrigin<'_>,
585 ) -> bool {
586 if matches!(origin, CrateOrigin::Injected) {
587 return true;
588 }
589
590 let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep);
591 match (extern_private, private_dep) {
592 (Some(false), _) | (_, Some(false)) | (None, None) => false,
595 (Some(true) | None, Some(true) | None) => true,
597 }
598 }
599
600 fn register_crate(
601 &mut self,
602 host_lib: Option<Library>,
603 origin: CrateOrigin<'_>,
604 lib: Library,
605 dep_kind: CrateDepKind,
606 name: Symbol,
607 private_dep: Option<bool>,
608 ) -> Result<CrateNum, CrateError> {
609 let _prof_timer =
610 self.sess.prof.generic_activity_with_arg("metadata_register_crate", name.as_str());
611
612 let Library { source, metadata } = lib;
613 let crate_root = metadata.get_root();
614 let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
615 let private_dep = self.is_private_dep(name, private_dep, origin);
616
617 let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?;
619 let cnum = feed.key();
620
621 info!(
622 "register crate `{}` (cnum = {}. private_dep = {})",
623 crate_root.name(),
624 cnum,
625 private_dep
626 );
627
628 let crate_paths;
631 let dep_root = if let Some(dep_root) = origin.dep_root() {
632 dep_root
633 } else {
634 crate_paths = CratePaths::new(crate_root.name(), source.clone());
635 &crate_paths
636 };
637
638 let cnum_map =
639 self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?;
640
641 let raw_proc_macros = if crate_root.is_proc_macro_crate() {
642 let temp_root;
643 let (dlsym_source, dlsym_root) = match &host_lib {
644 Some(host_lib) => (&host_lib.source, {
645 temp_root = host_lib.metadata.get_root();
646 &temp_root
647 }),
648 None => (&source, &crate_root),
649 };
650 let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
651 Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
652 } else {
653 None
654 };
655
656 let crate_metadata = CrateMetadata::new(
657 self.sess,
658 self.cstore,
659 metadata,
660 crate_root,
661 raw_proc_macros,
662 cnum,
663 cnum_map,
664 dep_kind,
665 source,
666 private_dep,
667 host_hash,
668 );
669
670 self.cstore.set_crate_data(cnum, crate_metadata);
671
672 Ok(cnum)
673 }
674
675 fn load_proc_macro<'b>(
676 &self,
677 locator: &mut CrateLocator<'b>,
678 path_kind: PathKind,
679 host_hash: Option<Svh>,
680 ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
681 where
682 'a: 'b,
683 {
684 let mut proc_macro_locator = locator.clone();
687
688 proc_macro_locator.is_proc_macro = true;
690
691 let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros {
693 proc_macro_locator.reset();
694 let result = match self.load(&mut proc_macro_locator)? {
695 Some(LoadResult::Previous(cnum)) => {
696 return Ok(Some((LoadResult::Previous(cnum), None)));
697 }
698 Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
699 None => return Ok(None),
700 };
701 locator.hash = host_hash;
702 (locator, result)
705 } else {
706 (&mut proc_macro_locator, None)
707 };
708
709 locator.reset();
712 locator.is_proc_macro = true;
713 locator.target = &self.sess.host;
714 locator.tuple = TargetTuple::from_tuple(config::host_tuple());
715 locator.filesearch = self.sess.host_filesearch();
716 locator.path_kind = path_kind;
717
718 let Some(host_result) = self.load(locator)? else {
719 return Ok(None);
720 };
721
722 Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros {
723 let host_result = match host_result {
724 LoadResult::Previous(..) => {
725 panic!("host and target proc macros must be loaded in lock-step")
726 }
727 LoadResult::Loaded(library) => library,
728 };
729 (target_result.unwrap(), Some(host_result))
730 } else {
731 (host_result, None)
732 }))
733 }
734
735 fn resolve_crate(
736 &mut self,
737 name: Symbol,
738 span: Span,
739 dep_kind: CrateDepKind,
740 origin: CrateOrigin<'_>,
741 ) -> Option<CrateNum> {
742 self.used_extern_options.insert(name);
743 match self.maybe_resolve_crate(name, dep_kind, origin) {
744 Ok(cnum) => {
745 self.cstore.set_used_recursively(cnum);
746 Some(cnum)
747 }
748 Err(err) => {
749 debug!("failed to resolve crate {} {:?}", name, dep_kind);
750 let missing_core = self
751 .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern)
752 .is_err();
753 err.report(self.sess, span, missing_core);
754 None
755 }
756 }
757 }
758
759 fn maybe_resolve_crate<'b>(
760 &'b mut self,
761 name: Symbol,
762 mut dep_kind: CrateDepKind,
763 origin: CrateOrigin<'b>,
764 ) -> Result<CrateNum, CrateError> {
765 info!("resolving crate `{}`", name);
766 if !name.as_str().is_ascii() {
767 return Err(CrateError::NonAsciiName(name));
768 }
769
770 let dep_root = origin.dep_root();
771 let dep = origin.dep();
772 let hash = dep.map(|d| d.hash);
773 let host_hash = dep.map(|d| d.host_hash).flatten();
774 let extra_filename = dep.map(|d| &d.extra_filename[..]);
775 let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
776 let private_dep = origin.private_dep();
777
778 let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
779 (LoadResult::Previous(cnum), None)
780 } else {
781 info!("falling back to a load");
782 let mut locator = CrateLocator::new(
783 self.sess,
784 &*self.cstore.metadata_loader,
785 name,
786 self.tcx.crate_types().iter().all(|c| *c == CrateType::Rlib),
789 hash,
790 extra_filename,
791 path_kind,
792 );
793
794 match self.load(&mut locator)? {
795 Some(res) => (res, None),
796 None => {
797 info!("falling back to loading proc_macro");
798 dep_kind = CrateDepKind::MacrosOnly;
799 match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
800 Some(res) => res,
801 None => return Err(locator.into_error(dep_root.cloned())),
802 }
803 }
804 }
805 };
806
807 match result {
808 (LoadResult::Previous(cnum), None) => {
809 info!("library for `{}` was loaded previously, cnum {cnum}", name);
810 let private_dep = self.is_private_dep(name, private_dep, origin);
815 let data = self.cstore.get_crate_data_mut(cnum);
816 if data.is_proc_macro_crate() {
817 dep_kind = CrateDepKind::MacrosOnly;
818 }
819 data.set_dep_kind(cmp::max(data.dep_kind(), dep_kind));
820 data.update_and_private_dep(private_dep);
821 Ok(cnum)
822 }
823 (LoadResult::Loaded(library), host_library) => {
824 info!("register newly loaded library for `{}`", name);
825 self.register_crate(host_library, origin, library, dep_kind, name, private_dep)
826 }
827 _ => panic!(),
828 }
829 }
830
831 fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
832 let Some(library) = locator.maybe_load_library_crate()? else {
833 return Ok(None);
834 };
835
836 let root = library.metadata.get_root();
841 let mut result = LoadResult::Loaded(library);
842 for (cnum, data) in self.cstore.iter_crate_data() {
843 if data.name() == root.name() && root.hash() == data.hash() {
844 assert!(locator.hash.is_none());
845 info!("load success, going to previous cnum: {}", cnum);
846 result = LoadResult::Previous(cnum);
847 break;
848 }
849 }
850 Ok(Some(result))
851 }
852
853 fn resolve_crate_deps(
855 &mut self,
856 dep_root: &CratePaths,
857 crate_root: &CrateRoot,
858 metadata: &MetadataBlob,
859 krate: CrateNum,
860 dep_kind: CrateDepKind,
861 parent_is_private: bool,
862 ) -> Result<CrateNumMap, CrateError> {
863 debug!(
864 "resolving deps of external crate `{}` with dep root `{}`",
865 crate_root.name(),
866 dep_root.name
867 );
868 if crate_root.is_proc_macro_crate() {
869 return Ok(CrateNumMap::new());
870 }
871
872 let deps = crate_root.decode_crate_deps(metadata);
876 let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
877 crate_num_map.push(krate);
878 for dep in deps {
879 info!(
880 "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}",
881 crate_root.name(),
882 dep.name,
883 dep.hash,
884 dep.extra_filename,
885 dep.is_private,
886 );
887 let dep_kind = match dep_kind {
888 CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
889 _ => dep.kind,
890 };
891 let cnum = self.maybe_resolve_crate(
892 dep.name,
893 dep_kind,
894 CrateOrigin::IndirectDependency {
895 dep_root,
896 parent_private: parent_is_private,
897 dep: &dep,
898 },
899 )?;
900 crate_num_map.push(cnum);
901 }
902
903 debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);
904 Ok(crate_num_map)
905 }
906
907 fn dlsym_proc_macros(
908 &self,
909 path: &Path,
910 stable_crate_id: StableCrateId,
911 ) -> Result<&'static [ProcMacro], CrateError> {
912 let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
913 debug!("trying to dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
914
915 unsafe {
916 let result = load_symbol_from_dylib::<*const &[ProcMacro]>(path, &sym_name);
917 match result {
918 Ok(result) => {
919 debug!("loaded dlsym proc_macros {} for symbol `{}`", path.display(), sym_name);
920 Ok(*result)
921 }
922 Err(err) => {
923 debug!(
924 "failed to dlsym proc_macros {} for symbol `{}`",
925 path.display(),
926 sym_name
927 );
928 Err(err.into())
929 }
930 }
931 }
932 }
933
934 fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
935 let only_rlib = self.tcx.crate_types().iter().all(|ct| *ct == CrateType::Rlib);
938 if only_rlib {
939 info!("panic runtime injection skipped, only generating rlib");
940 return;
941 }
942
943 let desired_strategy = self.sess.panic_strategy();
951 let mut runtime_found = false;
952 let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
953
954 let mut panic_runtimes = Vec::new();
955 for (cnum, data) in self.cstore.iter_crate_data() {
956 needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
957 if data.is_panic_runtime() {
958 panic_runtimes.push(cnum);
961 runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
962 }
963 }
964 for cnum in panic_runtimes {
965 self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
966 }
967
968 if !needs_panic_runtime || runtime_found {
972 return;
973 }
974
975 let name = match desired_strategy {
988 PanicStrategy::Unwind => sym::panic_unwind,
989 PanicStrategy::Abort => sym::panic_abort,
990 };
991 info!("panic runtime not found -- loading {}", name);
992
993 let Some(cnum) =
994 self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
995 else {
996 return;
997 };
998 let data = self.cstore.get_crate_data(cnum);
999
1000 if !data.is_panic_runtime() {
1003 self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
1004 }
1005 if data.required_panic_strategy() != Some(desired_strategy) {
1006 self.dcx()
1007 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
1008 }
1009
1010 self.cstore.injected_panic_runtime = Some(cnum);
1011 self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
1012 }
1013
1014 fn inject_profiler_runtime(&mut self) {
1015 let needs_profiler_runtime =
1016 self.sess.instrument_coverage() || self.sess.opts.cg.profile_generate.enabled();
1017 if !needs_profiler_runtime || self.sess.opts.unstable_opts.no_profiler_runtime {
1018 return;
1019 }
1020
1021 info!("loading profiler");
1022
1023 let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
1024 let Some(cnum) =
1025 self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected)
1026 else {
1027 return;
1028 };
1029 let data = self.cstore.get_crate_data(cnum);
1030
1031 if !data.is_profiler_runtime() {
1033 self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
1034 }
1035 }
1036
1037 fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
1038 self.cstore.has_global_allocator =
1039 match &*fn_spans(krate, Symbol::intern(&global_fn_name(sym::alloc))) {
1040 [span1, span2, ..] => {
1041 self.dcx()
1042 .emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
1043 true
1044 }
1045 spans => !spans.is_empty(),
1046 };
1047 self.cstore.has_alloc_error_handler = match &*fn_spans(
1048 krate,
1049 Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
1050 ) {
1051 [span1, span2, ..] => {
1052 self.dcx()
1053 .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
1054 true
1055 }
1056 spans => !spans.is_empty(),
1057 };
1058
1059 if !attr::contains_name(&krate.attrs, sym::needs_allocator)
1063 && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
1064 {
1065 return;
1066 }
1067
1068 let all_rlib = self.tcx.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
1072 if all_rlib {
1073 return;
1074 }
1075
1076 #[allow(rustc::symbol_intern_string_literal)]
1084 let this_crate = Symbol::intern("this crate");
1085
1086 let mut global_allocator = self.cstore.has_global_allocator.then_some(this_crate);
1087 for (_, data) in self.cstore.iter_crate_data() {
1088 if data.has_global_allocator() {
1089 match global_allocator {
1090 Some(other_crate) => {
1091 self.dcx().emit_err(errors::ConflictingGlobalAlloc {
1092 crate_name: data.name(),
1093 other_crate_name: other_crate,
1094 });
1095 }
1096 None => global_allocator = Some(data.name()),
1097 }
1098 }
1099 }
1100 let mut alloc_error_handler = self.cstore.has_alloc_error_handler.then_some(this_crate);
1101 for (_, data) in self.cstore.iter_crate_data() {
1102 if data.has_alloc_error_handler() {
1103 match alloc_error_handler {
1104 Some(other_crate) => {
1105 self.dcx().emit_err(errors::ConflictingAllocErrorHandler {
1106 crate_name: data.name(),
1107 other_crate_name: other_crate,
1108 });
1109 }
1110 None => alloc_error_handler = Some(data.name()),
1111 }
1112 }
1113 }
1114
1115 if global_allocator.is_some() {
1116 self.cstore.allocator_kind = Some(AllocatorKind::Global);
1117 } else {
1118 if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
1123 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
1124 {
1125 self.dcx().emit_err(errors::GlobalAllocRequired);
1126 }
1127 self.cstore.allocator_kind = Some(AllocatorKind::Default);
1128 }
1129
1130 if alloc_error_handler.is_some() {
1131 self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
1132 } else {
1133 self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
1136 }
1137 }
1138
1139 fn inject_forced_externs(&mut self) {
1140 for (name, entry) in self.sess.opts.externs.iter() {
1141 if entry.force {
1142 let name_interned = Symbol::intern(name);
1143 if !self.used_extern_options.contains(&name_interned) {
1144 self.resolve_crate(
1145 name_interned,
1146 DUMMY_SP,
1147 CrateDepKind::Explicit,
1148 CrateOrigin::Extern,
1149 );
1150 }
1151 }
1152 }
1153 }
1154
1155 fn inject_compiler_builtins(&mut self, krate: &ast::Crate) {
1157 if attr::contains_name(&krate.attrs, sym::compiler_builtins)
1159 || attr::contains_name(&krate.attrs, sym::no_core)
1160 {
1161 info!("`compiler_builtins` unneeded");
1162 return;
1163 }
1164
1165 for (cnum, cmeta) in self.cstore.iter_crate_data() {
1168 if cmeta.is_compiler_builtins() {
1169 info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection");
1170 return;
1171 }
1172 }
1173
1174 let Some(cnum) = self.resolve_crate(
1176 sym::compiler_builtins,
1177 krate.spans.inner_span.shrink_to_lo(),
1178 CrateDepKind::Explicit,
1179 CrateOrigin::Injected,
1180 ) else {
1181 info!("`compiler_builtins` not resolved");
1182 return;
1183 };
1184
1185 let cmeta = self.cstore.get_crate_data(cnum);
1187 if !cmeta.is_compiler_builtins() {
1188 self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() });
1189 }
1190 }
1191
1192 fn inject_dependency_if(
1193 &mut self,
1194 krate: CrateNum,
1195 what: &str,
1196 needs_dep: &dyn Fn(&CrateMetadata) -> bool,
1197 ) {
1198 if self.dcx().has_errors().is_some() {
1202 return;
1203 }
1204
1205 for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
1209 let data = self.cstore.get_crate_data(dep);
1210 if needs_dep(&data) {
1211 self.dcx().emit_err(errors::NoTransitiveNeedsDep {
1212 crate_name: self.cstore.get_crate_data(krate).name(),
1213 needs_crate_name: what,
1214 deps_crate_name: data.name(),
1215 });
1216 }
1217 }
1218
1219 for (cnum, data) in self.cstore.iter_crate_data_mut() {
1224 if needs_dep(data) {
1225 info!("injecting a dep from {} to {}", cnum, krate);
1226 data.add_dependency(krate);
1227 }
1228 }
1229 }
1230
1231 fn report_unused_deps(&mut self, krate: &ast::Crate) {
1232 let span = krate.spans.inner_span.shrink_to_lo();
1234 for (name, entry) in self.sess.opts.externs.iter() {
1236 if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
1237 continue;
1239 }
1240 if entry.nounused_dep || entry.force {
1241 continue;
1243 }
1244 let name_interned = Symbol::intern(name);
1245 if self.used_extern_options.contains(&name_interned) {
1246 continue;
1247 }
1248
1249 if self.sess.opts.json_unused_externs.is_enabled() {
1251 self.cstore.unused_externs.push(name_interned);
1252 continue;
1253 }
1254
1255 self.sess.psess.buffer_lint(
1256 lint::builtin::UNUSED_CRATE_DEPENDENCIES,
1257 span,
1258 ast::CRATE_NODE_ID,
1259 BuiltinLintDiag::UnusedCrateDependency {
1260 extern_crate: name_interned,
1261 local_crate: self.tcx.crate_name(LOCAL_CRATE),
1262 },
1263 );
1264 }
1265 }
1266
1267 fn report_future_incompatible_deps(&self, krate: &ast::Crate) {
1268 let name = self.tcx.crate_name(LOCAL_CRATE);
1269
1270 if name.as_str() == "wasm_bindgen" {
1271 let major = env::var("CARGO_PKG_VERSION_MAJOR")
1272 .ok()
1273 .and_then(|major| u64::from_str(&major).ok());
1274 let minor = env::var("CARGO_PKG_VERSION_MINOR")
1275 .ok()
1276 .and_then(|minor| u64::from_str(&minor).ok());
1277 let patch = env::var("CARGO_PKG_VERSION_PATCH")
1278 .ok()
1279 .and_then(|patch| u64::from_str(&patch).ok());
1280
1281 match (major, minor, patch) {
1282 (Some(1..), _, _) => return,
1284 (Some(0), Some(3..), _) => return,
1286 (Some(0), Some(2), Some(88..)) => return,
1288 (None, None, None) => return,
1290 _ => (),
1291 }
1292
1293 let span = krate.spans.inner_span.shrink_to_lo();
1295
1296 self.sess.dcx().emit_err(errors::WasmCAbi { span });
1297 }
1298 }
1299
1300 pub fn postprocess(&mut self, krate: &ast::Crate) {
1301 self.inject_compiler_builtins(krate);
1302 self.inject_forced_externs();
1303 self.inject_profiler_runtime();
1304 self.inject_allocator_crate(krate);
1305 self.inject_panic_runtime(krate);
1306
1307 self.report_unused_deps(krate);
1308 self.report_future_incompatible_deps(krate);
1309
1310 info!("{:?}", CrateDump(self.cstore));
1311 }
1312
1313 pub fn process_extern_crate(
1315 &mut self,
1316 item: &ast::Item,
1317 def_id: LocalDefId,
1318 definitions: &Definitions,
1319 ) -> Option<CrateNum> {
1320 match item.kind {
1321 ast::ItemKind::ExternCrate(orig_name, ident) => {
1322 debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", ident, orig_name);
1323 let name = match orig_name {
1324 Some(orig_name) => {
1325 validate_crate_name(self.sess, orig_name, Some(item.span));
1326 orig_name
1327 }
1328 None => ident.name,
1329 };
1330 let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
1331 CrateDepKind::MacrosOnly
1332 } else {
1333 CrateDepKind::Explicit
1334 };
1335
1336 let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?;
1337
1338 let path_len = definitions.def_path(def_id).data.len();
1339 self.cstore.update_extern_crate(
1340 cnum,
1341 ExternCrate {
1342 src: ExternCrateSource::Extern(def_id.to_def_id()),
1343 span: item.span,
1344 path_len,
1345 dependency_of: LOCAL_CRATE,
1346 },
1347 );
1348 Some(cnum)
1349 }
1350 _ => bug!(),
1351 }
1352 }
1353
1354 pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
1355 let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?;
1356
1357 self.cstore.update_extern_crate(
1358 cnum,
1359 ExternCrate {
1360 src: ExternCrateSource::Path,
1361 span,
1362 path_len: usize::MAX,
1364 dependency_of: LOCAL_CRATE,
1365 },
1366 );
1367
1368 Some(cnum)
1369 }
1370
1371 pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
1372 self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok()
1373 }
1374}
1375
1376fn fn_spans(krate: &ast::Crate, name: Symbol) -> Vec<Span> {
1377 struct Finder {
1378 name: Symbol,
1379 spans: Vec<Span>,
1380 }
1381 impl<'ast> visit::Visitor<'ast> for Finder {
1382 fn visit_item(&mut self, item: &'ast ast::Item) {
1383 if let Some(ident) = item.kind.ident()
1384 && ident.name == self.name
1385 && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1386 {
1387 self.spans.push(item.span);
1388 }
1389 visit::walk_item(self, item)
1390 }
1391 }
1392
1393 let mut f = Finder { name, spans: Vec::new() };
1394 visit::walk_crate(&mut f, krate);
1395 f.spans
1396}
1397
1398fn format_dlopen_err(e: &(dyn std::error::Error + 'static)) -> String {
1399 e.sources().map(|e| format!(": {e}")).collect()
1400}
1401
1402fn attempt_load_dylib(path: &Path) -> Result<libloading::Library, libloading::Error> {
1403 #[cfg(target_os = "aix")]
1404 if let Some(ext) = path.extension()
1405 && ext.eq("a")
1406 {
1407 let library_name = path.file_stem().expect("expect a library name");
1411 let mut archive_member = std::ffi::OsString::from("a(");
1412 archive_member.push(library_name);
1413 archive_member.push(".so)");
1414 let new_path = path.with_extension(archive_member);
1415
1416 let flags = libc::RTLD_LAZY | libc::RTLD_LOCAL | libc::RTLD_MEMBER;
1418 return unsafe { libloading::os::unix::Library::open(Some(&new_path), flags) }
1419 .map(|lib| lib.into());
1420 }
1421
1422 unsafe { libloading::Library::new(&path) }
1423}
1424
1425fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
1430 assert!(max_attempts > 0);
1431
1432 let mut last_error = None;
1433
1434 for attempt in 0..max_attempts {
1435 debug!("Attempt to load proc-macro `{}`.", path.display());
1436 match attempt_load_dylib(path) {
1437 Ok(lib) => {
1438 if attempt > 0 {
1439 debug!(
1440 "Loaded proc-macro `{}` after {} attempts.",
1441 path.display(),
1442 attempt + 1
1443 );
1444 }
1445 return Ok(lib);
1446 }
1447 Err(err) => {
1448 if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
1450 debug!("Failed to load proc-macro `{}`. Not retrying", path.display());
1451 let err = format_dlopen_err(&err);
1452 if let Some(err) = err.strip_prefix(&format!(": {}", path.display())) {
1455 return Err(err.to_string());
1456 }
1457 return Err(err);
1458 }
1459
1460 last_error = Some(err);
1461 std::thread::sleep(Duration::from_millis(100));
1462 debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
1463 }
1464 }
1465 }
1466
1467 debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
1468
1469 let last_error = last_error.unwrap();
1470 let message = if let Some(src) = last_error.source() {
1471 format!("{} ({src}) (retried {max_attempts} times)", format_dlopen_err(&last_error))
1472 } else {
1473 format!("{} (retried {max_attempts} times)", format_dlopen_err(&last_error))
1474 };
1475 Err(message)
1476}
1477
1478pub enum DylibError {
1479 DlOpen(String, String),
1480 DlSym(String, String),
1481}
1482
1483impl From<DylibError> for CrateError {
1484 fn from(err: DylibError) -> CrateError {
1485 match err {
1486 DylibError::DlOpen(path, err) => CrateError::DlOpen(path, err),
1487 DylibError::DlSym(path, err) => CrateError::DlSym(path, err),
1488 }
1489 }
1490}
1491
1492pub unsafe fn load_symbol_from_dylib<T: Copy>(
1493 path: &Path,
1494 sym_name: &str,
1495) -> Result<T, DylibError> {
1496 let path = try_canonicalize(path).unwrap();
1498 let lib =
1499 load_dylib(&path, 5).map_err(|err| DylibError::DlOpen(path.display().to_string(), err))?;
1500
1501 let sym = unsafe { lib.get::<T>(sym_name.as_bytes()) }
1502 .map_err(|err| DylibError::DlSym(path.display().to_string(), format_dlopen_err(&err)))?;
1503
1504 let sym = unsafe { sym.into_raw() };
1507 std::mem::forget(lib);
1508
1509 Ok(*sym)
1510}