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