• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! Validates all used crates and extern libraries and loads their metadata
2 
3 use crate::errors;
4 use crate::locator::{CrateError, CrateLocator, CratePaths};
5 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
6 
7 use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind};
8 use rustc_ast::{self as ast, *};
9 use rustc_data_structures::fx::FxHashSet;
10 use rustc_data_structures::svh::Svh;
11 use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard, WriteGuard};
12 use rustc_expand::base::SyntaxExtension;
13 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
14 use rustc_hir::definitions::Definitions;
15 use rustc_index::IndexVec;
16 use rustc_middle::ty::TyCtxt;
17 use rustc_session::config::{self, CrateType, ExternLocation};
18 use rustc_session::cstore::ExternCrateSource;
19 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate};
20 use rustc_session::lint;
21 use rustc_session::output::validate_crate_name;
22 use rustc_session::search_paths::PathKind;
23 use rustc_session::Session;
24 use rustc_span::edition::Edition;
25 use rustc_span::symbol::{sym, Symbol};
26 use rustc_span::{Span, DUMMY_SP};
27 use rustc_target::spec::{PanicStrategy, TargetTriple};
28 
29 use proc_macro::bridge::client::ProcMacro;
30 use std::error::Error;
31 use std::ops::Fn;
32 use std::path::Path;
33 use std::time::Duration;
34 use std::{cmp, env, iter};
35 
36 pub struct CStore {
37     metas: IndexVec<CrateNum, Option<Box<CrateMetadata>>>,
38     injected_panic_runtime: Option<CrateNum>,
39     /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
40     /// If the above is true, then this field denotes the kind of the found allocator.
41     allocator_kind: Option<AllocatorKind>,
42     /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
43     /// If the above is true, then this field denotes the kind of the found allocator.
44     alloc_error_handler_kind: Option<AllocatorKind>,
45     /// This crate has a `#[global_allocator]` item.
46     has_global_allocator: bool,
47     /// This crate has a `#[alloc_error_handler]` item.
48     has_alloc_error_handler: bool,
49 
50     /// The interned [StableCrateId]s.
51     pub(crate) stable_crate_ids: StableCrateIdMap,
52 
53     /// Unused externs of the crate
54     unused_externs: Vec<Symbol>,
55 }
56 
57 impl std::fmt::Debug for CStore {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result58     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59         f.debug_struct("CStore").finish_non_exhaustive()
60     }
61 }
62 
63 pub struct CrateLoader<'a, 'tcx: 'a> {
64     // Immutable configuration.
65     tcx: TyCtxt<'tcx>,
66     // Mutable output.
67     cstore: &'a mut CStore,
68     used_extern_options: &'a mut FxHashSet<Symbol>,
69 }
70 
71 impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
72     type Target = TyCtxt<'tcx>;
73 
deref(&self) -> &Self::Target74     fn deref(&self) -> &Self::Target {
75         &self.tcx
76     }
77 }
78 
79 pub enum LoadedMacro {
80     MacroDef(ast::Item, Edition),
81     ProcMacro(SyntaxExtension),
82 }
83 
84 pub(crate) struct Library {
85     pub source: CrateSource,
86     pub metadata: MetadataBlob,
87 }
88 
89 enum LoadResult {
90     Previous(CrateNum),
91     Loaded(Library),
92 }
93 
94 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
95 #[derive(Clone, Copy)]
96 pub(crate) struct CrateMetadataRef<'a> {
97     pub cdata: &'a CrateMetadata,
98     pub cstore: &'a CStore,
99 }
100 
101 impl std::ops::Deref for CrateMetadataRef<'_> {
102     type Target = CrateMetadata;
103 
deref(&self) -> &Self::Target104     fn deref(&self) -> &Self::Target {
105         self.cdata
106     }
107 }
108 
109 struct CrateDump<'a>(&'a CStore);
110 
111 impl<'a> std::fmt::Debug for CrateDump<'a> {
fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result112     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113         writeln!(fmt, "resolved crates:")?;
114         for (cnum, data) in self.0.iter_crate_data() {
115             writeln!(fmt, "  name: {}", data.name())?;
116             writeln!(fmt, "  cnum: {cnum}")?;
117             writeln!(fmt, "  hash: {}", data.hash())?;
118             writeln!(fmt, "  reqd: {:?}", data.dep_kind())?;
119             let CrateSource { dylib, rlib, rmeta } = data.source();
120             if let Some(dylib) = dylib {
121                 writeln!(fmt, "  dylib: {}", dylib.0.display())?;
122             }
123             if let Some(rlib) = rlib {
124                 writeln!(fmt, "   rlib: {}", rlib.0.display())?;
125             }
126             if let Some(rmeta) = rmeta {
127                 writeln!(fmt, "   rmeta: {}", rmeta.0.display())?;
128             }
129         }
130         Ok(())
131     }
132 }
133 
134 impl CStore {
from_tcx(tcx: TyCtxt<'_>) -> MappedReadGuard<'_, CStore>135     pub fn from_tcx(tcx: TyCtxt<'_>) -> MappedReadGuard<'_, CStore> {
136         ReadGuard::map(tcx.untracked().cstore.read(), |cstore| {
137             cstore.as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
138         })
139     }
140 
from_tcx_mut(tcx: TyCtxt<'_>) -> MappedWriteGuard<'_, CStore>141     pub fn from_tcx_mut(tcx: TyCtxt<'_>) -> MappedWriteGuard<'_, CStore> {
142         WriteGuard::map(tcx.untracked().cstore.write(), |cstore| {
143             cstore.untracked_as_any().downcast_mut().expect("`tcx.cstore` is not a `CStore`")
144         })
145     }
146 
intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError>147     fn intern_stable_crate_id(&mut self, root: &CrateRoot) -> Result<CrateNum, CrateError> {
148         assert_eq!(self.metas.len(), self.stable_crate_ids.len());
149         let num = CrateNum::new(self.stable_crate_ids.len());
150         if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
151             // Check for (potential) conflicts with the local crate
152             if existing == LOCAL_CRATE {
153                 Err(CrateError::SymbolConflictsCurrent(root.name()))
154             } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
155             {
156                 let crate_name0 = root.name();
157                 Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
158             } else {
159                 Err(CrateError::NotFound(root.name()))
160             }
161         } else {
162             self.metas.push(None);
163             self.stable_crate_ids.insert(root.stable_crate_id(), num);
164             Ok(num)
165         }
166     }
167 
has_crate_data(&self, cnum: CrateNum) -> bool168     pub fn has_crate_data(&self, cnum: CrateNum) -> bool {
169         self.metas[cnum].is_some()
170     }
171 
get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_>172     pub(crate) fn get_crate_data(&self, cnum: CrateNum) -> CrateMetadataRef<'_> {
173         let cdata = self.metas[cnum]
174             .as_ref()
175             .unwrap_or_else(|| panic!("Failed to get crate data for {cnum:?}"));
176         CrateMetadataRef { cdata, cstore: self }
177     }
178 
set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata)179     fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
180         assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
181         self.metas[cnum] = Some(Box::new(data));
182     }
183 
iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)>184     pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
185         self.metas
186             .iter_enumerated()
187             .filter_map(|(cnum, data)| data.as_deref().map(|data| (cnum, data)))
188     }
189 
push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum)190     fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
191         if !deps.contains(&cnum) {
192             let data = self.get_crate_data(cnum);
193             for dep in data.dependencies() {
194                 if dep != cnum {
195                     self.push_dependencies_in_postorder(deps, dep);
196                 }
197             }
198 
199             deps.push(cnum);
200         }
201     }
202 
crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum>203     pub(crate) fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
204         let mut deps = Vec::new();
205         if cnum == LOCAL_CRATE {
206             for (cnum, _) in self.iter_crate_data() {
207                 self.push_dependencies_in_postorder(&mut deps, cnum);
208             }
209         } else {
210             self.push_dependencies_in_postorder(&mut deps, cnum);
211         }
212         deps
213     }
214 
crate_dependencies_in_reverse_postorder(&self, cnum: CrateNum) -> Vec<CrateNum>215     fn crate_dependencies_in_reverse_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
216         let mut deps = self.crate_dependencies_in_postorder(cnum);
217         deps.reverse();
218         deps
219     }
220 
injected_panic_runtime(&self) -> Option<CrateNum>221     pub(crate) fn injected_panic_runtime(&self) -> Option<CrateNum> {
222         self.injected_panic_runtime
223     }
224 
allocator_kind(&self) -> Option<AllocatorKind>225     pub(crate) fn allocator_kind(&self) -> Option<AllocatorKind> {
226         self.allocator_kind
227     }
228 
alloc_error_handler_kind(&self) -> Option<AllocatorKind>229     pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
230         self.alloc_error_handler_kind
231     }
232 
has_global_allocator(&self) -> bool233     pub(crate) fn has_global_allocator(&self) -> bool {
234         self.has_global_allocator
235     }
236 
has_alloc_error_handler(&self) -> bool237     pub(crate) fn has_alloc_error_handler(&self) -> bool {
238         self.has_alloc_error_handler
239     }
240 
report_unused_deps(&self, tcx: TyCtxt<'_>)241     pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
242         let json_unused_externs = tcx.sess.opts.json_unused_externs;
243 
244         // We put the check for the option before the lint_level_at_node call
245         // because the call mutates internal state and introducing it
246         // leads to some ui tests failing.
247         if !json_unused_externs.is_enabled() {
248             return;
249         }
250         let level = tcx
251             .lint_level_at_node(lint::builtin::UNUSED_CRATE_DEPENDENCIES, rustc_hir::CRATE_HIR_ID)
252             .0;
253         if level != lint::Level::Allow {
254             let unused_externs =
255                 self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
256             let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
257             tcx.sess.parse_sess.span_diagnostic.emit_unused_externs(
258                 level,
259                 json_unused_externs.is_loud(),
260                 &unused_externs,
261             );
262         }
263     }
264 
new(sess: &Session) -> CStore265     pub fn new(sess: &Session) -> CStore {
266         let mut stable_crate_ids = StableCrateIdMap::default();
267         stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE);
268         CStore {
269             // We add an empty entry for LOCAL_CRATE (which maps to zero) in
270             // order to make array indices in `metas` match with the
271             // corresponding `CrateNum`. This first entry will always remain
272             // `None`.
273             metas: IndexVec::from_iter(iter::once(None)),
274             injected_panic_runtime: None,
275             allocator_kind: None,
276             alloc_error_handler_kind: None,
277             has_global_allocator: false,
278             has_alloc_error_handler: false,
279             stable_crate_ids,
280             unused_externs: Vec::new(),
281         }
282     }
283 }
284 
285 impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
new( tcx: TyCtxt<'tcx>, cstore: &'a mut CStore, used_extern_options: &'a mut FxHashSet<Symbol>, ) -> Self286     pub fn new(
287         tcx: TyCtxt<'tcx>,
288         cstore: &'a mut CStore,
289         used_extern_options: &'a mut FxHashSet<Symbol>,
290     ) -> Self {
291         CrateLoader { tcx, cstore, used_extern_options }
292     }
293 
existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum>294     fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
295         for (cnum, data) in self.cstore.iter_crate_data() {
296             if data.name() != name {
297                 trace!("{} did not match {}", data.name(), name);
298                 continue;
299             }
300 
301             match hash {
302                 Some(hash) if hash == data.hash() => return Some(cnum),
303                 Some(hash) => {
304                     debug!("actual hash {} did not match expected {}", hash, data.hash());
305                     continue;
306                 }
307                 None => {}
308             }
309 
310             // When the hash is None we're dealing with a top-level dependency
311             // in which case we may have a specification on the command line for
312             // this library. Even though an upstream library may have loaded
313             // something of the same name, we have to make sure it was loaded
314             // from the exact same location as well.
315             //
316             // We're also sure to compare *paths*, not actual byte slices. The
317             // `source` stores paths which are normalized which may be different
318             // from the strings on the command line.
319             let source = self.cstore.get_crate_data(cnum).cdata.source();
320             if let Some(entry) = self.sess.opts.externs.get(name.as_str()) {
321                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
322                 if let Some(mut files) = entry.files() {
323                     if files.any(|l| {
324                         let l = l.canonicalized();
325                         source.dylib.as_ref().map(|(p, _)| p) == Some(l)
326                             || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
327                             || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
328                     }) {
329                         return Some(cnum);
330                     }
331                 }
332                 continue;
333             }
334 
335             // Alright, so we've gotten this far which means that `data` has the
336             // right name, we don't have a hash, and we don't have a --extern
337             // pointing for ourselves. We're still not quite yet done because we
338             // have to make sure that this crate was found in the crate lookup
339             // path (this is a top-level dependency) as we don't want to
340             // implicitly load anything inside the dependency lookup path.
341             let prev_kind = source
342                 .dylib
343                 .as_ref()
344                 .or(source.rlib.as_ref())
345                 .or(source.rmeta.as_ref())
346                 .expect("No sources for crate")
347                 .1;
348             if kind.matches(prev_kind) {
349                 return Some(cnum);
350             } else {
351                 debug!(
352                     "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
353                     name, kind, prev_kind
354                 );
355             }
356         }
357 
358         None
359     }
360 
register_crate( &mut self, host_lib: Option<Library>, root: Option<&CratePaths>, lib: Library, dep_kind: CrateDepKind, name: Symbol, private_dep: Option<bool>, ) -> Result<CrateNum, CrateError>361     fn register_crate(
362         &mut self,
363         host_lib: Option<Library>,
364         root: Option<&CratePaths>,
365         lib: Library,
366         dep_kind: CrateDepKind,
367         name: Symbol,
368         private_dep: Option<bool>,
369     ) -> Result<CrateNum, CrateError> {
370         let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
371 
372         let Library { source, metadata } = lib;
373         let crate_root = metadata.get_root();
374         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
375 
376         let private_dep = self
377             .sess
378             .opts
379             .externs
380             .get(name.as_str())
381             .map_or(private_dep.unwrap_or(false), |e| e.is_private_dep)
382             && private_dep.unwrap_or(true);
383 
384         // Claim this crate number and cache it
385         let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
386 
387         info!(
388             "register crate `{}` (cnum = {}. private_dep = {})",
389             crate_root.name(),
390             cnum,
391             private_dep
392         );
393 
394         // Maintain a reference to the top most crate.
395         // Stash paths for top-most crate locally if necessary.
396         let crate_paths;
397         let root = if let Some(root) = root {
398             root
399         } else {
400             crate_paths = CratePaths::new(crate_root.name(), source.clone());
401             &crate_paths
402         };
403 
404         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, dep_kind)?;
405 
406         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
407             let temp_root;
408             let (dlsym_source, dlsym_root) = match &host_lib {
409                 Some(host_lib) => (&host_lib.source, {
410                     temp_root = host_lib.metadata.get_root();
411                     &temp_root
412                 }),
413                 None => (&source, &crate_root),
414             };
415             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
416             Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?)
417         } else {
418             None
419         };
420 
421         let crate_metadata = CrateMetadata::new(
422             self.sess,
423             &self.cstore,
424             metadata,
425             crate_root,
426             raw_proc_macros,
427             cnum,
428             cnum_map,
429             dep_kind,
430             source,
431             private_dep,
432             host_hash,
433         );
434 
435         self.cstore.set_crate_data(cnum, crate_metadata);
436 
437         Ok(cnum)
438     }
439 
load_proc_macro<'b>( &self, locator: &mut CrateLocator<'b>, path_kind: PathKind, host_hash: Option<Svh>, ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError> where 'a: 'b,440     fn load_proc_macro<'b>(
441         &self,
442         locator: &mut CrateLocator<'b>,
443         path_kind: PathKind,
444         host_hash: Option<Svh>,
445     ) -> Result<Option<(LoadResult, Option<Library>)>, CrateError>
446     where
447         'a: 'b,
448     {
449         // Use a new crate locator so trying to load a proc macro doesn't affect the error
450         // message we emit
451         let mut proc_macro_locator = locator.clone();
452 
453         // Try to load a proc macro
454         proc_macro_locator.is_proc_macro = true;
455 
456         // Load the proc macro crate for the target
457         let (locator, target_result) = if self.sess.opts.unstable_opts.dual_proc_macros {
458             proc_macro_locator.reset();
459             let result = match self.load(&mut proc_macro_locator)? {
460                 Some(LoadResult::Previous(cnum)) => {
461                     return Ok(Some((LoadResult::Previous(cnum), None)));
462                 }
463                 Some(LoadResult::Loaded(library)) => Some(LoadResult::Loaded(library)),
464                 None => return Ok(None),
465             };
466             locator.hash = host_hash;
467             // Use the locator when looking for the host proc macro crate, as that is required
468             // so we want it to affect the error message
469             (locator, result)
470         } else {
471             (&mut proc_macro_locator, None)
472         };
473 
474         // Load the proc macro crate for the host
475 
476         locator.reset();
477         locator.is_proc_macro = true;
478         locator.target = &self.sess.host;
479         locator.triple = TargetTriple::from_triple(config::host_triple());
480         locator.filesearch = self.sess.host_filesearch(path_kind);
481 
482         let Some(host_result) = self.load(locator)? else {
483             return Ok(None);
484         };
485 
486         Ok(Some(if self.sess.opts.unstable_opts.dual_proc_macros {
487             let host_result = match host_result {
488                 LoadResult::Previous(..) => {
489                     panic!("host and target proc macros must be loaded in lock-step")
490                 }
491                 LoadResult::Loaded(library) => library,
492             };
493             (target_result.unwrap(), Some(host_result))
494         } else {
495             (host_result, None)
496         }))
497     }
498 
resolve_crate( &mut self, name: Symbol, span: Span, dep_kind: CrateDepKind, ) -> Option<CrateNum>499     fn resolve_crate(
500         &mut self,
501         name: Symbol,
502         span: Span,
503         dep_kind: CrateDepKind,
504     ) -> Option<CrateNum> {
505         self.used_extern_options.insert(name);
506         match self.maybe_resolve_crate(name, dep_kind, None) {
507             Ok(cnum) => Some(cnum),
508             Err(err) => {
509                 let missing_core =
510                     self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err();
511                 err.report(&self.sess, span, missing_core);
512                 None
513             }
514         }
515     }
516 
maybe_resolve_crate<'b>( &'b mut self, name: Symbol, mut dep_kind: CrateDepKind, dep: Option<(&'b CratePaths, &'b CrateDep)>, ) -> Result<CrateNum, CrateError>517     fn maybe_resolve_crate<'b>(
518         &'b mut self,
519         name: Symbol,
520         mut dep_kind: CrateDepKind,
521         dep: Option<(&'b CratePaths, &'b CrateDep)>,
522     ) -> Result<CrateNum, CrateError> {
523         info!("resolving crate `{}`", name);
524         if !name.as_str().is_ascii() {
525             return Err(CrateError::NonAsciiName(name));
526         }
527         let (root, hash, host_hash, extra_filename, path_kind, private_dep) = match dep {
528             Some((root, dep)) => (
529                 Some(root),
530                 Some(dep.hash),
531                 dep.host_hash,
532                 Some(&dep.extra_filename[..]),
533                 PathKind::Dependency,
534                 Some(dep.is_private),
535             ),
536             None => (None, None, None, None, PathKind::Crate, None),
537         };
538         let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
539             (LoadResult::Previous(cnum), None)
540         } else {
541             info!("falling back to a load");
542             let metadata_loader = self.tcx.metadata_loader(()).borrow();
543             let mut locator = CrateLocator::new(
544                 self.sess,
545                 &**metadata_loader,
546                 name,
547                 hash,
548                 extra_filename,
549                 false, // is_host
550                 path_kind,
551             );
552 
553             match self.load(&mut locator)? {
554                 Some(res) => (res, None),
555                 None => {
556                     dep_kind = CrateDepKind::MacrosOnly;
557                     match self.load_proc_macro(&mut locator, path_kind, host_hash)? {
558                         Some(res) => res,
559                         None => return Err(locator.into_error(root.cloned())),
560                     }
561                 }
562             }
563         };
564 
565         match result {
566             (LoadResult::Previous(cnum), None) => {
567                 let data = self.cstore.get_crate_data(cnum);
568                 if data.is_proc_macro_crate() {
569                     dep_kind = CrateDepKind::MacrosOnly;
570                 }
571                 data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind));
572                 if let Some(private_dep) = private_dep {
573                     data.update_and_private_dep(private_dep);
574                 }
575                 Ok(cnum)
576             }
577             (LoadResult::Loaded(library), host_library) => {
578                 self.register_crate(host_library, root, library, dep_kind, name, private_dep)
579             }
580             _ => panic!(),
581         }
582     }
583 
load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError>584     fn load(&self, locator: &mut CrateLocator<'_>) -> Result<Option<LoadResult>, CrateError> {
585         let Some(library) = locator.maybe_load_library_crate()? else {
586             return Ok(None);
587         };
588 
589         // In the case that we're loading a crate, but not matching
590         // against a hash, we could load a crate which has the same hash
591         // as an already loaded crate. If this is the case prevent
592         // duplicates by just using the first crate.
593         //
594         // Note that we only do this for target triple crates, though, as we
595         // don't want to match a host crate against an equivalent target one
596         // already loaded.
597         let root = library.metadata.get_root();
598         // FIXME: why is this condition necessary? It was adding in #33625 but I
599         // don't know why and the original author doesn't remember ...
600         let can_reuse_cratenum =
601             locator.triple == self.sess.opts.target_triple || locator.is_proc_macro;
602         Ok(Some(if can_reuse_cratenum {
603             let mut result = LoadResult::Loaded(library);
604             for (cnum, data) in self.cstore.iter_crate_data() {
605                 if data.name() == root.name() && root.hash() == data.hash() {
606                     assert!(locator.hash.is_none());
607                     info!("load success, going to previous cnum: {}", cnum);
608                     result = LoadResult::Previous(cnum);
609                     break;
610                 }
611             }
612             result
613         } else {
614             LoadResult::Loaded(library)
615         }))
616     }
617 
update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate)618     fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
619         let cmeta = self.cstore.get_crate_data(cnum);
620         if cmeta.update_extern_crate(extern_crate) {
621             // Propagate the extern crate info to dependencies if it was updated.
622             let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
623             for dep_cnum in cmeta.dependencies() {
624                 self.update_extern_crate(dep_cnum, extern_crate);
625             }
626         }
627     }
628 
629     // Go through the crate metadata and load any crates that it references
resolve_crate_deps( &mut self, root: &CratePaths, crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, dep_kind: CrateDepKind, ) -> Result<CrateNumMap, CrateError>630     fn resolve_crate_deps(
631         &mut self,
632         root: &CratePaths,
633         crate_root: &CrateRoot,
634         metadata: &MetadataBlob,
635         krate: CrateNum,
636         dep_kind: CrateDepKind,
637     ) -> Result<CrateNumMap, CrateError> {
638         debug!("resolving deps of external crate");
639         if crate_root.is_proc_macro_crate() {
640             return Ok(CrateNumMap::new());
641         }
642 
643         // The map from crate numbers in the crate we're resolving to local crate numbers.
644         // We map 0 and all other holes in the map to our parent crate. The "additional"
645         // self-dependencies should be harmless.
646         let deps = crate_root.decode_crate_deps(metadata);
647         let mut crate_num_map = CrateNumMap::with_capacity(1 + deps.len());
648         crate_num_map.push(krate);
649         for dep in deps {
650             info!(
651                 "resolving dep crate {} hash: `{}` extra filename: `{}`",
652                 dep.name, dep.hash, dep.extra_filename
653             );
654             let dep_kind = match dep_kind {
655                 CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly,
656                 _ => dep.kind,
657             };
658             let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((root, &dep)))?;
659             crate_num_map.push(cnum);
660         }
661 
662         debug!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate, crate_num_map);
663         Ok(crate_num_map)
664     }
665 
dlsym_proc_macros( &self, path: &Path, stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacro], CrateError>666     fn dlsym_proc_macros(
667         &self,
668         path: &Path,
669         stable_crate_id: StableCrateId,
670     ) -> Result<&'static [ProcMacro], CrateError> {
671         // Make sure the path contains a / or the linker will search for it.
672         let path = env::current_dir().unwrap().join(path);
673         let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
674 
675         let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
676         let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
677             .map_err(|err| CrateError::DlSym(err.to_string()))?;
678 
679         // Intentionally leak the dynamic library. We can't ever unload it
680         // since the library can make things that will live arbitrarily long.
681         let sym = unsafe { sym.into_raw() };
682         std::mem::forget(lib);
683 
684         Ok(unsafe { **sym })
685     }
686 
inject_panic_runtime(&mut self, krate: &ast::Crate)687     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
688         // If we're only compiling an rlib, then there's no need to select a
689         // panic runtime, so we just skip this section entirely.
690         let any_non_rlib = self.sess.crate_types().iter().any(|ct| *ct != CrateType::Rlib);
691         if !any_non_rlib {
692             info!("panic runtime injection skipped, only generating rlib");
693             return;
694         }
695 
696         // If we need a panic runtime, we try to find an existing one here. At
697         // the same time we perform some general validation of the DAG we've got
698         // going such as ensuring everything has a compatible panic strategy.
699         //
700         // The logic for finding the panic runtime here is pretty much the same
701         // as the allocator case with the only addition that the panic strategy
702         // compilation mode also comes into play.
703         let desired_strategy = self.sess.panic_strategy();
704         let mut runtime_found = false;
705         let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
706 
707         for (cnum, data) in self.cstore.iter_crate_data() {
708             needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
709             if data.is_panic_runtime() {
710                 // Inject a dependency from all #![needs_panic_runtime] to this
711                 // #![panic_runtime] crate.
712                 self.inject_dependency_if(cnum, "a panic runtime", &|data| {
713                     data.needs_panic_runtime()
714                 });
715                 runtime_found = runtime_found || data.dep_kind() == CrateDepKind::Explicit;
716             }
717         }
718 
719         // If an explicitly linked and matching panic runtime was found, or if
720         // we just don't need one at all, then we're done here and there's
721         // nothing else to do.
722         if !needs_panic_runtime || runtime_found {
723             return;
724         }
725 
726         // By this point we know that we (a) need a panic runtime and (b) no
727         // panic runtime was explicitly linked. Here we just load an appropriate
728         // default runtime for our panic strategy and then inject the
729         // dependencies.
730         //
731         // We may resolve to an already loaded crate (as the crate may not have
732         // been explicitly linked prior to this) and we may re-inject
733         // dependencies again, but both of those situations are fine.
734         //
735         // Also note that we have yet to perform validation of the crate graph
736         // in terms of everyone has a compatible panic runtime format, that's
737         // performed later as part of the `dependency_format` module.
738         let name = match desired_strategy {
739             PanicStrategy::Unwind => sym::panic_unwind,
740             PanicStrategy::Abort => sym::panic_abort,
741         };
742         info!("panic runtime not found -- loading {}", name);
743 
744         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
745         let data = self.cstore.get_crate_data(cnum);
746 
747         // Sanity check the loaded crate to ensure it is indeed a panic runtime
748         // and the panic strategy is indeed what we thought it was.
749         if !data.is_panic_runtime() {
750             self.sess.emit_err(errors::CrateNotPanicRuntime { crate_name: name });
751         }
752         if data.required_panic_strategy() != Some(desired_strategy) {
753             self.sess
754                 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
755         }
756 
757         self.cstore.injected_panic_runtime = Some(cnum);
758         self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
759     }
760 
inject_profiler_runtime(&mut self, krate: &ast::Crate)761     fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
762         if self.sess.opts.unstable_opts.no_profiler_runtime
763             || !(self.sess.instrument_coverage()
764                 || self.sess.opts.unstable_opts.profile
765                 || self.sess.opts.cg.profile_generate.enabled())
766         {
767             return;
768         }
769 
770         info!("loading profiler");
771 
772         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
773         if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) {
774             self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
775         }
776 
777         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
778         let data = self.cstore.get_crate_data(cnum);
779 
780         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
781         if !data.is_profiler_runtime() {
782             self.sess.emit_err(errors::NotProfilerRuntime { crate_name: name });
783         }
784     }
785 
inject_allocator_crate(&mut self, krate: &ast::Crate)786     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
787         self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
788             [span1, span2, ..] => {
789                 self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
790                 true
791             }
792             spans => !spans.is_empty(),
793         };
794         self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
795             [span1, span2, ..] => {
796                 self.sess
797                     .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
798                 true
799             }
800             spans => !spans.is_empty(),
801         };
802 
803         // Check to see if we actually need an allocator. This desire comes
804         // about through the `#![needs_allocator]` attribute and is typically
805         // written down in liballoc.
806         if !attr::contains_name(&krate.attrs, sym::needs_allocator)
807             && !self.cstore.iter_crate_data().any(|(_, data)| data.needs_allocator())
808         {
809             return;
810         }
811 
812         // At this point we've determined that we need an allocator. Let's see
813         // if our compilation session actually needs an allocator based on what
814         // we're emitting.
815         let all_rlib = self.sess.crate_types().iter().all(|ct| matches!(*ct, CrateType::Rlib));
816         if all_rlib {
817             return;
818         }
819 
820         // Ok, we need an allocator. Not only that but we're actually going to
821         // create an artifact that needs one linked in. Let's go find the one
822         // that we're going to link in.
823         //
824         // First up we check for global allocators. Look at the crate graph here
825         // and see what's a global allocator, including if we ourselves are a
826         // global allocator.
827         let mut global_allocator =
828             self.cstore.has_global_allocator.then(|| Symbol::intern("this crate"));
829         for (_, data) in self.cstore.iter_crate_data() {
830             if data.has_global_allocator() {
831                 match global_allocator {
832                     Some(other_crate) => {
833                         self.sess.emit_err(errors::ConflictingGlobalAlloc {
834                             crate_name: data.name(),
835                             other_crate_name: other_crate,
836                         });
837                     }
838                     None => global_allocator = Some(data.name()),
839                 }
840             }
841         }
842         let mut alloc_error_handler =
843             self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
844         for (_, data) in self.cstore.iter_crate_data() {
845             if data.has_alloc_error_handler() {
846                 match alloc_error_handler {
847                     Some(other_crate) => {
848                         self.sess.emit_err(errors::ConflictingAllocErrorHandler {
849                             crate_name: data.name(),
850                             other_crate_name: other_crate,
851                         });
852                     }
853                     None => alloc_error_handler = Some(data.name()),
854                 }
855             }
856         }
857 
858         if global_allocator.is_some() {
859             self.cstore.allocator_kind = Some(AllocatorKind::Global);
860         } else {
861             // Ok we haven't found a global allocator but we still need an
862             // allocator. At this point our allocator request is typically fulfilled
863             // by the standard library, denoted by the `#![default_lib_allocator]`
864             // attribute.
865             if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
866                 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
867             {
868                 self.sess.emit_err(errors::GlobalAllocRequired);
869             }
870             self.cstore.allocator_kind = Some(AllocatorKind::Default);
871         }
872 
873         if alloc_error_handler.is_some() {
874             self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
875         } else {
876             // The alloc crate provides a default allocation error handler if
877             // one isn't specified.
878             self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
879         }
880     }
881 
inject_forced_externs(&mut self)882     fn inject_forced_externs(&mut self) {
883         for (name, entry) in self.sess.opts.externs.iter() {
884             if entry.force {
885                 let name_interned = Symbol::intern(name);
886                 if !self.used_extern_options.contains(&name_interned) {
887                     self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
888                 }
889             }
890         }
891     }
892 
inject_dependency_if( &self, krate: CrateNum, what: &str, needs_dep: &dyn Fn(&CrateMetadata) -> bool, )893     fn inject_dependency_if(
894         &self,
895         krate: CrateNum,
896         what: &str,
897         needs_dep: &dyn Fn(&CrateMetadata) -> bool,
898     ) {
899         // don't perform this validation if the session has errors, as one of
900         // those errors may indicate a circular dependency which could cause
901         // this to stack overflow.
902         if self.sess.has_errors().is_some() {
903             return;
904         }
905 
906         // Before we inject any dependencies, make sure we don't inject a
907         // circular dependency by validating that this crate doesn't
908         // transitively depend on any crates satisfying `needs_dep`.
909         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
910             let data = self.cstore.get_crate_data(dep);
911             if needs_dep(&data) {
912                 self.sess.emit_err(errors::NoTransitiveNeedsDep {
913                     crate_name: self.cstore.get_crate_data(krate).name(),
914                     needs_crate_name: what,
915                     deps_crate_name: data.name(),
916                 });
917             }
918         }
919 
920         // All crates satisfying `needs_dep` do not explicitly depend on the
921         // crate provided for this compile, but in order for this compilation to
922         // be successfully linked we need to inject a dependency (to order the
923         // crates on the command line correctly).
924         for (cnum, data) in self.cstore.iter_crate_data() {
925             if needs_dep(data) {
926                 info!("injecting a dep from {} to {}", cnum, krate);
927                 data.add_dependency(krate);
928             }
929         }
930     }
931 
report_unused_deps(&mut self, krate: &ast::Crate)932     fn report_unused_deps(&mut self, krate: &ast::Crate) {
933         // Make a point span rather than covering the whole file
934         let span = krate.spans.inner_span.shrink_to_lo();
935         // Complain about anything left over
936         for (name, entry) in self.sess.opts.externs.iter() {
937             if let ExternLocation::FoundInLibrarySearchDirectories = entry.location {
938                 // Don't worry about pathless `--extern foo` sysroot references
939                 continue;
940             }
941             if entry.nounused_dep || entry.force {
942                 // We're not worried about this one
943                 continue;
944             }
945             let name_interned = Symbol::intern(name);
946             if self.used_extern_options.contains(&name_interned) {
947                 continue;
948             }
949 
950             // Got a real unused --extern
951             if self.sess.opts.json_unused_externs.is_enabled() {
952                 self.cstore.unused_externs.push(name_interned);
953                 continue;
954             }
955 
956             self.sess.parse_sess.buffer_lint(
957                     lint::builtin::UNUSED_CRATE_DEPENDENCIES,
958                     span,
959                     ast::CRATE_NODE_ID,
960                     format!(
961                         "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
962                         name,
963                         self.tcx.crate_name(LOCAL_CRATE),
964                         name),
965                 );
966         }
967     }
968 
postprocess(&mut self, krate: &ast::Crate)969     pub fn postprocess(&mut self, krate: &ast::Crate) {
970         self.inject_forced_externs();
971         self.inject_profiler_runtime(krate);
972         self.inject_allocator_crate(krate);
973         self.inject_panic_runtime(krate);
974 
975         self.report_unused_deps(krate);
976 
977         info!("{:?}", CrateDump(&self.cstore));
978     }
979 
process_extern_crate( &mut self, item: &ast::Item, def_id: LocalDefId, definitions: &Definitions, ) -> Option<CrateNum>980     pub fn process_extern_crate(
981         &mut self,
982         item: &ast::Item,
983         def_id: LocalDefId,
984         definitions: &Definitions,
985     ) -> Option<CrateNum> {
986         match item.kind {
987             ast::ItemKind::ExternCrate(orig_name) => {
988                 debug!(
989                     "resolving extern crate stmt. ident: {} orig_name: {:?}",
990                     item.ident, orig_name
991                 );
992                 let name = match orig_name {
993                     Some(orig_name) => {
994                         validate_crate_name(self.sess, orig_name, Some(item.span));
995                         orig_name
996                     }
997                     None => item.ident.name,
998                 };
999                 let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
1000                     CrateDepKind::MacrosOnly
1001                 } else {
1002                     CrateDepKind::Explicit
1003                 };
1004 
1005                 let cnum = self.resolve_crate(name, item.span, dep_kind)?;
1006 
1007                 let path_len = definitions.def_path(def_id).data.len();
1008                 self.update_extern_crate(
1009                     cnum,
1010                     ExternCrate {
1011                         src: ExternCrateSource::Extern(def_id.to_def_id()),
1012                         span: item.span,
1013                         path_len,
1014                         dependency_of: LOCAL_CRATE,
1015                     },
1016                 );
1017                 Some(cnum)
1018             }
1019             _ => bug!(),
1020         }
1021     }
1022 
process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum>1023     pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
1024         let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?;
1025 
1026         self.update_extern_crate(
1027             cnum,
1028             ExternCrate {
1029                 src: ExternCrateSource::Path,
1030                 span,
1031                 // to have the least priority in `update_extern_crate`
1032                 path_len: usize::MAX,
1033                 dependency_of: LOCAL_CRATE,
1034             },
1035         );
1036 
1037         Some(cnum)
1038     }
1039 
maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum>1040     pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option<CrateNum> {
1041         self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
1042     }
1043 }
1044 
global_allocator_spans(krate: &ast::Crate) -> Vec<Span>1045 fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
1046     struct Finder {
1047         name: Symbol,
1048         spans: Vec<Span>,
1049     }
1050     impl<'ast> visit::Visitor<'ast> for Finder {
1051         fn visit_item(&mut self, item: &'ast ast::Item) {
1052             if item.ident.name == self.name
1053                 && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1054             {
1055                 self.spans.push(item.span);
1056             }
1057             visit::walk_item(self, item)
1058         }
1059     }
1060 
1061     let name = Symbol::intern(&global_fn_name(sym::alloc));
1062     let mut f = Finder { name, spans: Vec::new() };
1063     visit::walk_crate(&mut f, krate);
1064     f.spans
1065 }
1066 
alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span>1067 fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
1068     struct Finder {
1069         name: Symbol,
1070         spans: Vec<Span>,
1071     }
1072     impl<'ast> visit::Visitor<'ast> for Finder {
1073         fn visit_item(&mut self, item: &'ast ast::Item) {
1074             if item.ident.name == self.name
1075                 && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
1076             {
1077                 self.spans.push(item.span);
1078             }
1079             visit::walk_item(self, item)
1080         }
1081     }
1082 
1083     let name = Symbol::intern(alloc_error_handler_name(AllocatorKind::Global));
1084     let mut f = Finder { name, spans: Vec::new() };
1085     visit::walk_crate(&mut f, krate);
1086     f.spans
1087 }
1088 
1089 // On Windows the compiler would sometimes intermittently fail to open the
1090 // proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
1091 // system still holds a lock on the file, so we retry a few times before calling it
1092 // an error.
load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String>1093 fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
1094     assert!(max_attempts > 0);
1095 
1096     let mut last_error = None;
1097 
1098     for attempt in 0..max_attempts {
1099         match unsafe { libloading::Library::new(&path) } {
1100             Ok(lib) => {
1101                 if attempt > 0 {
1102                     debug!(
1103                         "Loaded proc-macro `{}` after {} attempts.",
1104                         path.display(),
1105                         attempt + 1
1106                     );
1107                 }
1108                 return Ok(lib);
1109             }
1110             Err(err) => {
1111                 // Only try to recover from this specific error.
1112                 if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
1113                     return Err(err.to_string());
1114                 }
1115 
1116                 last_error = Some(err);
1117                 std::thread::sleep(Duration::from_millis(100));
1118                 debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
1119             }
1120         }
1121     }
1122 
1123     debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
1124 
1125     let last_error = last_error.unwrap();
1126     let message = if let Some(src) = last_error.source() {
1127         format!("{last_error} ({src}) (retried {max_attempts} times)")
1128     } else {
1129         format!("{last_error} (retried {max_attempts} times)")
1130     };
1131     Err(message)
1132 }
1133