1 //! Validates all used crates and extern libraries and loads their metadata
3 use crate::dynamic_lib
::DynamicLibrary
;
4 use crate::locator
::{CrateError, CrateLocator, CratePaths}
;
5 use crate::rmeta
::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob}
;
7 use rustc_ast
::expand
::allocator
::AllocatorKind
;
8 use rustc_ast
::{self as ast, *}
;
9 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
10 use rustc_data_structures
::svh
::Svh
;
11 use rustc_data_structures
::sync
::Lrc
;
12 use rustc_expand
::base
::SyntaxExtension
;
13 use rustc_hir
::def_id
::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE}
;
14 use rustc_hir
::definitions
::Definitions
;
15 use rustc_index
::vec
::IndexVec
;
16 use rustc_middle
::middle
::cstore
::{CrateDepKind, CrateSource, ExternCrate}
;
17 use rustc_middle
::middle
::cstore
::{ExternCrateSource, MetadataLoaderDyn}
;
18 use rustc_middle
::ty
::TyCtxt
;
19 use rustc_serialize
::json
::ToJson
;
20 use rustc_session
::config
::{self, CrateType, ExternLocation}
;
21 use rustc_session
::lint
::{self, BuiltinLintDiagnostics, ExternDepSpec}
;
22 use rustc_session
::output
::validate_crate_name
;
23 use rustc_session
::search_paths
::PathKind
;
24 use rustc_session
::Session
;
25 use rustc_span
::edition
::Edition
;
26 use rustc_span
::symbol
::{sym, Symbol}
;
27 use rustc_span
::{Span, DUMMY_SP}
;
28 use rustc_target
::spec
::{PanicStrategy, TargetTriple}
;
30 use proc_macro
::bridge
::client
::ProcMacro
;
31 use std
::collections
::BTreeMap
;
34 use tracing
::{debug, info}
;
38 metas
: IndexVec
<CrateNum
, Option
<Lrc
<CrateMetadata
>>>,
39 injected_panic_runtime
: Option
<CrateNum
>,
40 /// This crate needs an allocator and either provides it itself, or finds it in a dependency.
41 /// If the above is true, then this field denotes the kind of the found allocator.
42 allocator_kind
: Option
<AllocatorKind
>,
43 /// This crate has a `#[global_allocator]` item.
44 has_global_allocator
: bool
,
46 /// This map is used to verify we get no hash conflicts between
47 /// `StableCrateId` values.
48 stable_crate_ids
: FxHashMap
<StableCrateId
, CrateNum
>,
50 /// Unused externs of the crate
51 unused_externs
: Vec
<Symbol
>,
54 impl std
::fmt
::Debug
for CStore
{
55 fn fmt(&self, f
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
56 f
.debug_struct("CStore").finish_non_exhaustive()
60 pub struct CrateLoader
<'a
> {
61 // Immutable configuration.
63 metadata_loader
: Box
<MetadataLoaderDyn
>,
64 local_crate_name
: Symbol
,
67 used_extern_options
: FxHashSet
<Symbol
>,
70 pub enum LoadedMacro
{
71 MacroDef(ast
::Item
, Edition
),
72 ProcMacro(SyntaxExtension
),
75 crate struct Library
{
76 pub source
: CrateSource
,
77 pub metadata
: MetadataBlob
,
85 /// A reference to `CrateMetadata` that can also give access to whole crate store when necessary.
86 #[derive(Clone, Copy)]
87 crate struct CrateMetadataRef
<'a
> {
88 pub cdata
: &'a CrateMetadata
,
89 pub cstore
: &'a CStore
,
92 impl std
::ops
::Deref
for CrateMetadataRef
<'_
> {
93 type Target
= CrateMetadata
;
95 fn deref(&self) -> &Self::Target
{
100 struct CrateDump
<'a
>(&'a CStore
);
102 impl<'a
> std
::fmt
::Debug
for CrateDump
<'a
> {
103 fn fmt(&self, fmt
: &mut std
::fmt
::Formatter
<'_
>) -> std
::fmt
::Result
{
104 writeln
!(fmt
, "resolved crates:")?
;
105 // `iter_crate_data` does not allow returning values. Thus we use a mutable variable here
106 // that aggregates the value (and any errors that could happen).
107 let mut res
= Ok(());
108 self.0.iter_crate_data
(|cnum
, data
| {
111 writeln
!(fmt
, " name: {}", data
.name())?
;
112 writeln
!(fmt
, " cnum: {}", cnum
)?
;
113 writeln
!(fmt
, " hash: {}", data
.hash())?
;
114 writeln
!(fmt
, " reqd: {:?}", data
.dep_kind())?
;
115 let CrateSource { dylib, rlib, rmeta }
= data
.source();
116 if let Some(dylib
) = dylib
{
117 writeln
!(fmt
, " dylib: {}", dylib
.0.display())?
;
119 if let Some(rlib
) = rlib
{
120 writeln
!(fmt
, " rlib: {}", rlib
.0.display())?
;
122 if let Some(rmeta
) = rmeta
{
123 writeln
!(fmt
, " rmeta: {}", rmeta
.0.display())?
;
133 pub fn from_tcx(tcx
: TyCtxt
<'_
>) -> &CStore
{
134 tcx
.cstore_untracked()
136 .downcast_ref
::<CStore
>()
137 .expect("`tcx.cstore` is not a `CStore`")
140 fn alloc_new_crate_num(&mut self) -> CrateNum
{
141 self.metas
.push(None
);
142 CrateNum
::new(self.metas
.len() - 1)
145 crate fn get_crate_data(&self, cnum
: CrateNum
) -> CrateMetadataRef
<'_
> {
146 let cdata
= self.metas
[cnum
]
148 .unwrap_or_else(|| panic
!("Failed to get crate data for {:?}", cnum
));
149 CrateMetadataRef { cdata, cstore: self }
152 fn set_crate_data(&mut self, cnum
: CrateNum
, data
: CrateMetadata
) {
153 assert
!(self.metas
[cnum
].is_none(), "Overwriting crate metadata entry");
154 self.metas
[cnum
] = Some(Lrc
::new(data
));
157 crate fn iter_crate_data(&self, mut f
: impl FnMut(CrateNum
, &CrateMetadata
)) {
158 for (cnum
, data
) in self.metas
.iter_enumerated() {
159 if let Some(data
) = data
{
165 fn push_dependencies_in_postorder(&self, deps
: &mut Vec
<CrateNum
>, cnum
: CrateNum
) {
166 if !deps
.contains(&cnum
) {
167 let data
= self.get_crate_data(cnum
);
168 for &dep
in data
.dependencies().iter() {
170 self.push_dependencies_in_postorder(deps
, dep
);
178 crate fn crate_dependencies_in_postorder(&self, cnum
: CrateNum
) -> Vec
<CrateNum
> {
179 let mut deps
= Vec
::new();
180 if cnum
== LOCAL_CRATE
{
181 self.iter_crate_data(|cnum
, _
| self.push_dependencies_in_postorder(&mut deps
, cnum
));
183 self.push_dependencies_in_postorder(&mut deps
, cnum
);
188 fn crate_dependencies_in_reverse_postorder(&self, cnum
: CrateNum
) -> Vec
<CrateNum
> {
189 let mut deps
= self.crate_dependencies_in_postorder(cnum
);
194 crate fn injected_panic_runtime(&self) -> Option
<CrateNum
> {
195 self.injected_panic_runtime
198 crate fn allocator_kind(&self) -> Option
<AllocatorKind
> {
202 crate fn has_global_allocator(&self) -> bool
{
203 self.has_global_allocator
206 pub fn report_unused_deps(&self, tcx
: TyCtxt
<'_
>) {
207 // We put the check for the option before the lint_level_at_node call
208 // because the call mutates internal state and introducing it
209 // leads to some ui tests failing.
210 if !tcx
.sess
.opts
.json_unused_externs
{
214 .lint_level_at_node(lint
::builtin
::UNUSED_CRATE_DEPENDENCIES
, rustc_hir
::CRATE_HIR_ID
)
216 if level
!= lint
::Level
::Allow
{
218 self.unused_externs
.iter().map(|ident
| ident
.to_ident_string()).collect
::<Vec
<_
>>();
219 let unused_externs
= unused_externs
.iter().map(String
::as_str
).collect
::<Vec
<&str>>();
223 .emit_unused_externs(level
.as_str(), &unused_externs
);
228 impl<'a
> CrateLoader
<'a
> {
231 metadata_loader
: Box
<MetadataLoaderDyn
>,
232 local_crate_name
: &str,
234 let mut stable_crate_ids
= FxHashMap
::default();
235 stable_crate_ids
.insert(sess
.local_stable_crate_id(), LOCAL_CRATE
);
240 local_crate_name
: Symbol
::intern(local_crate_name
),
242 // We add an empty entry for LOCAL_CRATE (which maps to zero) in
243 // order to make array indices in `metas` match with the
244 // corresponding `CrateNum`. This first entry will always remain
246 metas
: IndexVec
::from_elem_n(None
, 1),
247 injected_panic_runtime
: None
,
248 allocator_kind
: None
,
249 has_global_allocator
: false,
251 unused_externs
: Vec
::new(),
253 used_extern_options
: Default
::default(),
257 pub fn cstore(&self) -> &CStore
{
261 pub fn into_cstore(self) -> CStore
{
265 fn existing_match(&self, name
: Symbol
, hash
: Option
<Svh
>, kind
: PathKind
) -> Option
<CrateNum
> {
267 self.cstore
.iter_crate_data(|cnum
, data
| {
268 if data
.name() != name
{
269 tracing
::trace
!("{} did not match {}", data
.name(), name
);
274 Some(hash
) if hash
== data
.hash() => {
279 debug
!("actual hash {} did not match expected {}", hash
, data
.hash());
285 // When the hash is None we're dealing with a top-level dependency
286 // in which case we may have a specification on the command line for
287 // this library. Even though an upstream library may have loaded
288 // something of the same name, we have to make sure it was loaded
289 // from the exact same location as well.
291 // We're also sure to compare *paths*, not actual byte slices. The
292 // `source` stores paths which are normalized which may be different
293 // from the strings on the command line.
294 let source
= self.cstore
.get_crate_data(cnum
).cdata
.source();
295 if let Some(entry
) = self.sess
.opts
.externs
.get(&name
.as_str()) {
296 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
297 if let Some(mut files
) = entry
.files() {
299 let l
= l
.canonicalized();
300 source
.dylib
.as_ref().map(|(p
, _
)| p
) == Some(l
)
301 || source
.rlib
.as_ref().map(|(p
, _
)| p
) == Some(l
)
302 || source
.rmeta
.as_ref().map(|(p
, _
)| p
) == Some(l
)
310 // Alright, so we've gotten this far which means that `data` has the
311 // right name, we don't have a hash, and we don't have a --extern
312 // pointing for ourselves. We're still not quite yet done because we
313 // have to make sure that this crate was found in the crate lookup
314 // path (this is a top-level dependency) as we don't want to
315 // implicitly load anything inside the dependency lookup path.
316 let prev_kind
= source
319 .or(source
.rlib
.as_ref())
320 .or(source
.rmeta
.as_ref())
321 .expect("No sources for crate")
323 if kind
.matches(prev_kind
) {
327 "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
328 name
, kind
, prev_kind
335 fn verify_no_symbol_conflicts(&self, root
: &CrateRoot
<'_
>) -> Result
<(), CrateError
> {
336 // Check for (potential) conflicts with the local crate
337 if self.sess
.local_stable_crate_id() == root
.stable_crate_id() {
338 return Err(CrateError
::SymbolConflictsCurrent(root
.name()));
341 // Check for conflicts with any crate loaded so far
342 let mut res
= Ok(());
343 self.cstore
.iter_crate_data(|_
, other
| {
344 if other
.stable_crate_id() == root
.stable_crate_id() && // same stable crate id
345 other
.hash() != root
.hash()
348 res
= Err(CrateError
::SymbolConflictsOthers(root
.name()));
355 fn verify_no_stable_crate_id_hash_conflicts(
357 root
: &CrateRoot
<'_
>,
359 ) -> Result
<(), CrateError
> {
360 if let Some(existing
) = self.cstore
.stable_crate_ids
.insert(root
.stable_crate_id(), cnum
) {
361 let crate_name0
= root
.name();
362 let crate_name1
= self.cstore
.get_crate_data(existing
).name();
363 return Err(CrateError
::StableCrateIdCollision(crate_name0
, crate_name1
));
371 host_lib
: Option
<Library
>,
372 root
: Option
<&CratePaths
>,
374 dep_kind
: CrateDepKind
,
376 ) -> Result
<CrateNum
, CrateError
> {
377 let _prof_timer
= self.sess
.prof
.generic_activity("metadata_register_crate");
379 let Library { source, metadata }
= lib
;
380 let crate_root
= metadata
.get_root();
381 let host_hash
= host_lib
.as_ref().map(|lib
| lib
.metadata
.get_root().hash());
384 self.sess
.opts
.externs
.get(&name
.as_str()).map_or(false, |e
| e
.is_private_dep
);
386 // Claim this crate number and cache it
387 let cnum
= self.cstore
.alloc_new_crate_num();
390 "register crate `{}` (cnum = {}. private_dep = {})",
396 // Maintain a reference to the top most crate.
397 // Stash paths for top-most crate locally if necessary.
399 let root
= if let Some(root
) = root
{
402 crate_paths
= CratePaths
::new(crate_root
.name(), source
.clone());
406 let cnum_map
= self.resolve_crate_deps(root
, &crate_root
, &metadata
, cnum
, dep_kind
)?
;
408 let raw_proc_macros
= if crate_root
.is_proc_macro_crate() {
410 let (dlsym_source
, dlsym_root
) = match &host_lib
{
411 Some(host_lib
) => (&host_lib
.source
, {
412 temp_root
= host_lib
.metadata
.get_root();
415 None
=> (&source
, &crate_root
),
417 let dlsym_dylib
= dlsym_source
.dylib
.as_ref().expect("no dylib for a proc-macro crate");
418 Some(self.dlsym_proc_macros(&dlsym_dylib
.0, dlsym_root
.stable_crate_id())?
)
423 // Perform some verification *after* resolve_crate_deps() above is
424 // known to have been successful. It seems that - in error cases - the
425 // cstore can be in a temporarily invalid state between cnum allocation
426 // and dependency resolution and the verification code would produce
427 // ICEs in that case (see #83045).
428 self.verify_no_symbol_conflicts(&crate_root
)?
;
429 self.verify_no_stable_crate_id_hash_conflicts(&crate_root
, cnum
)?
;
431 let crate_metadata
= CrateMetadata
::new(
444 self.cstore
.set_crate_data(cnum
, crate_metadata
);
449 fn load_proc_macro
<'b
>(
451 locator
: &mut CrateLocator
<'b
>,
453 ) -> Result
<Option
<(LoadResult
, Option
<Library
>)>, CrateError
>
457 // Use a new crate locator so trying to load a proc macro doesn't affect the error
459 let mut proc_macro_locator
= locator
.clone();
461 // Try to load a proc macro
462 proc_macro_locator
.is_proc_macro
= Some(true);
464 // Load the proc macro crate for the target
465 let (locator
, target_result
) = if self.sess
.opts
.debugging_opts
.dual_proc_macros
{
466 proc_macro_locator
.reset();
467 let result
= match self.load(&mut proc_macro_locator
)?
{
468 Some(LoadResult
::Previous(cnum
)) => {
469 return Ok(Some((LoadResult
::Previous(cnum
), None
)));
471 Some(LoadResult
::Loaded(library
)) => Some(LoadResult
::Loaded(library
)),
472 None
=> return Ok(None
),
474 locator
.hash
= locator
.host_hash
;
475 // Use the locator when looking for the host proc macro crate, as that is required
476 // so we want it to affect the error message
479 (&mut proc_macro_locator
, None
)
482 // Load the proc macro crate for the host
485 locator
.is_proc_macro
= Some(true);
486 locator
.target
= &self.sess
.host
;
487 locator
.triple
= TargetTriple
::from_triple(config
::host_triple());
488 locator
.filesearch
= self.sess
.host_filesearch(path_kind
);
490 let host_result
= match self.load(locator
)?
{
491 Some(host_result
) => host_result
,
492 None
=> return Ok(None
),
495 Ok(Some(if self.sess
.opts
.debugging_opts
.dual_proc_macros
{
496 let host_result
= match host_result
{
497 LoadResult
::Previous(..) => {
498 panic
!("host and target proc macros must be loaded in lock-step")
500 LoadResult
::Loaded(library
) => library
,
502 (target_result
.unwrap(), Some(host_result
))
508 fn resolve_crate
<'b
>(
512 dep_kind
: CrateDepKind
,
513 dep
: Option
<(&'b CratePaths
, &'b CrateDep
)>,
516 self.used_extern_options
.insert(name
);
518 self.maybe_resolve_crate(name
, dep_kind
, dep
).unwrap_or_else(|err
| {
520 self.maybe_resolve_crate(sym
::core
, CrateDepKind
::Explicit
, None
).is_err();
521 err
.report(&self.sess
, span
, missing_core
)
525 fn maybe_resolve_crate
<'b
>(
528 mut dep_kind
: CrateDepKind
,
529 dep
: Option
<(&'b CratePaths
, &'b CrateDep
)>,
530 ) -> Result
<CrateNum
, CrateError
> {
531 info
!("resolving crate `{}`", name
);
532 if !name
.as_str().is_ascii() {
533 return Err(CrateError
::NonAsciiName(name
));
535 let (root
, hash
, host_hash
, extra_filename
, path_kind
) = match dep
{
536 Some((root
, dep
)) => (
540 Some(&dep
.extra_filename
[..]),
541 PathKind
::Dependency
,
543 None
=> (None
, None
, None
, None
, PathKind
::Crate
),
545 let result
= if let Some(cnum
) = self.existing_match(name
, hash
, path_kind
) {
546 (LoadResult
::Previous(cnum
), None
)
548 info
!("falling back to a load");
549 let mut locator
= CrateLocator
::new(
551 &*self.metadata_loader
,
559 Some(false), // is_proc_macro
562 match self.load(&mut locator
)?
{
563 Some(res
) => (res
, None
),
565 dep_kind
= CrateDepKind
::MacrosOnly
;
566 match self.load_proc_macro(&mut locator
, path_kind
)?
{
568 None
=> return Err(locator
.into_error()),
575 (LoadResult
::Previous(cnum
), None
) => {
576 let data
= self.cstore
.get_crate_data(cnum
);
577 if data
.is_proc_macro_crate() {
578 dep_kind
= CrateDepKind
::MacrosOnly
;
580 data
.update_dep_kind(|data_dep_kind
| cmp
::max(data_dep_kind
, dep_kind
));
583 (LoadResult
::Loaded(library
), host_library
) => {
584 self.register_crate(host_library
, root
, library
, dep_kind
, name
)
590 fn load(&self, locator
: &mut CrateLocator
<'_
>) -> Result
<Option
<LoadResult
>, CrateError
> {
591 let library
= match locator
.maybe_load_library_crate()?
{
592 Some(library
) => library
,
593 None
=> return Ok(None
),
596 // In the case that we're loading a crate, but not matching
597 // against a hash, we could load a crate which has the same hash
598 // as an already loaded crate. If this is the case prevent
599 // duplicates by just using the first crate.
601 // Note that we only do this for target triple crates, though, as we
602 // don't want to match a host crate against an equivalent target one
604 let root
= library
.metadata
.get_root();
605 // FIXME: why is this condition necessary? It was adding in #33625 but I
606 // don't know why and the original author doesn't remember ...
607 let can_reuse_cratenum
=
608 locator
.triple
== self.sess
.opts
.target_triple
|| locator
.is_proc_macro
== Some(true);
609 Ok(Some(if can_reuse_cratenum
{
610 let mut result
= LoadResult
::Loaded(library
);
611 self.cstore
.iter_crate_data(|cnum
, data
| {
612 if data
.name() == root
.name() && root
.hash() == data
.hash() {
613 assert
!(locator
.hash
.is_none());
614 info
!("load success, going to previous cnum: {}", cnum
);
615 result
= LoadResult
::Previous(cnum
);
620 LoadResult
::Loaded(library
)
624 fn update_extern_crate(&self, cnum
: CrateNum
, extern_crate
: ExternCrate
) {
625 let cmeta
= self.cstore
.get_crate_data(cnum
);
626 if cmeta
.update_extern_crate(extern_crate
) {
627 // Propagate the extern crate info to dependencies if it was updated.
628 let extern_crate
= ExternCrate { dependency_of: cnum, ..extern_crate }
;
629 for &dep_cnum
in cmeta
.dependencies().iter() {
630 self.update_extern_crate(dep_cnum
, extern_crate
);
635 // Go through the crate metadata and load any crates that it references
636 fn resolve_crate_deps(
639 crate_root
: &CrateRoot
<'_
>,
640 metadata
: &MetadataBlob
,
642 dep_kind
: CrateDepKind
,
643 ) -> Result
<CrateNumMap
, CrateError
> {
644 debug
!("resolving deps of external crate");
645 if crate_root
.is_proc_macro_crate() {
646 return Ok(CrateNumMap
::new());
649 // The map from crate numbers in the crate we're resolving to local crate numbers.
650 // We map 0 and all other holes in the map to our parent crate. The "additional"
651 // self-dependencies should be harmless.
652 let deps
= crate_root
.decode_crate_deps(metadata
);
653 let mut crate_num_map
= CrateNumMap
::with_capacity(1 + deps
.len());
654 crate_num_map
.push(krate
);
657 "resolving dep crate {} hash: `{}` extra filename: `{}`",
658 dep
.name
, dep
.hash
, dep
.extra_filename
660 let dep_kind
= match dep_kind
{
661 CrateDepKind
::MacrosOnly
=> CrateDepKind
::MacrosOnly
,
664 let cnum
= self.maybe_resolve_crate(dep
.name
, dep_kind
, Some((root
, &dep
)))?
;
665 crate_num_map
.push(cnum
);
668 debug
!("resolve_crate_deps: cnum_map for {:?} is {:?}", krate
, crate_num_map
);
672 fn dlsym_proc_macros(
675 stable_crate_id
: StableCrateId
,
676 ) -> Result
<&'
static [ProcMacro
], CrateError
> {
677 // Make sure the path contains a / or the linker will search for it.
678 let path
= env
::current_dir().unwrap().join(path
);
679 let lib
= match DynamicLibrary
::open(&path
) {
681 Err(s
) => return Err(CrateError
::DlOpen(s
)),
684 let sym
= self.sess
.generate_proc_macro_decls_symbol(stable_crate_id
);
686 let sym
= match lib
.symbol(&sym
) {
688 Err(s
) => return Err(CrateError
::DlSym(s
)),
690 *(sym
as *const &[ProcMacro
])
693 // Intentionally leak the dynamic library. We can't ever unload it
694 // since the library can make things that will live arbitrarily long.
695 std
::mem
::forget(lib
);
700 fn inject_panic_runtime(&mut self, krate
: &ast
::Crate
) {
701 // If we're only compiling an rlib, then there's no need to select a
702 // panic runtime, so we just skip this section entirely.
703 let any_non_rlib
= self.sess
.crate_types().iter().any(|ct
| *ct
!= CrateType
::Rlib
);
705 info
!("panic runtime injection skipped, only generating rlib");
709 // If we need a panic runtime, we try to find an existing one here. At
710 // the same time we perform some general validation of the DAG we've got
711 // going such as ensuring everything has a compatible panic strategy.
713 // The logic for finding the panic runtime here is pretty much the same
714 // as the allocator case with the only addition that the panic strategy
715 // compilation mode also comes into play.
716 let desired_strategy
= self.sess
.panic_strategy();
717 let mut runtime_found
= false;
718 let mut needs_panic_runtime
=
719 self.sess
.contains_name(&krate
.attrs
, sym
::needs_panic_runtime
);
721 self.cstore
.iter_crate_data(|cnum
, data
| {
722 needs_panic_runtime
= needs_panic_runtime
|| data
.needs_panic_runtime();
723 if data
.is_panic_runtime() {
724 // Inject a dependency from all #![needs_panic_runtime] to this
725 // #![panic_runtime] crate.
726 self.inject_dependency_if(cnum
, "a panic runtime", &|data
| {
727 data
.needs_panic_runtime()
729 runtime_found
= runtime_found
|| data
.dep_kind() == CrateDepKind
::Explicit
;
733 // If an explicitly linked and matching panic runtime was found, or if
734 // we just don't need one at all, then we're done here and there's
735 // nothing else to do.
736 if !needs_panic_runtime
|| runtime_found
{
740 // By this point we know that we (a) need a panic runtime and (b) no
741 // panic runtime was explicitly linked. Here we just load an appropriate
742 // default runtime for our panic strategy and then inject the
745 // We may resolve to an already loaded crate (as the crate may not have
746 // been explicitly linked prior to this) and we may re-inject
747 // dependencies again, but both of those situations are fine.
749 // Also note that we have yet to perform validation of the crate graph
750 // in terms of everyone has a compatible panic runtime format, that's
751 // performed later as part of the `dependency_format` module.
752 let name
= match desired_strategy
{
753 PanicStrategy
::Unwind
=> sym
::panic_unwind
,
754 PanicStrategy
::Abort
=> sym
::panic_abort
,
756 info
!("panic runtime not found -- loading {}", name
);
758 let cnum
= self.resolve_crate(name
, DUMMY_SP
, CrateDepKind
::Implicit
, None
);
759 let data
= self.cstore
.get_crate_data(cnum
);
761 // Sanity check the loaded crate to ensure it is indeed a panic runtime
762 // and the panic strategy is indeed what we thought it was.
763 if !data
.is_panic_runtime() {
764 self.sess
.err(&format
!("the crate `{}` is not a panic runtime", name
));
766 if data
.panic_strategy() != desired_strategy
{
767 self.sess
.err(&format
!(
768 "the crate `{}` does not have the panic \
771 desired_strategy
.desc()
775 self.cstore
.injected_panic_runtime
= Some(cnum
);
776 self.inject_dependency_if(cnum
, "a panic runtime", &|data
| data
.needs_panic_runtime());
779 fn inject_profiler_runtime(&mut self, krate
: &ast
::Crate
) {
780 let profiler_runtime
= &self.sess
.opts
.debugging_opts
.profiler_runtime
;
782 if !(profiler_runtime
.is_some()
783 && (self.sess
.instrument_coverage()
784 || self.sess
.opts
.debugging_opts
.profile
785 || self.sess
.opts
.cg
.profile_generate
.enabled()))
790 info
!("loading profiler");
792 let name
= Symbol
::intern(profiler_runtime
.as_ref().unwrap());
793 if name
== sym
::profiler_builtins
&& self.sess
.contains_name(&krate
.attrs
, sym
::no_core
) {
795 "`profiler_builtins` crate (required by compiler options) \
796 is not compatible with crate attribute `#![no_core]`",
800 let cnum
= self.resolve_crate(name
, DUMMY_SP
, CrateDepKind
::Implicit
, None
);
801 let data
= self.cstore
.get_crate_data(cnum
);
803 // Sanity check the loaded crate to ensure it is indeed a profiler runtime
804 if !data
.is_profiler_runtime() {
805 self.sess
.err(&format
!("the crate `{}` is not a profiler runtime", name
));
809 fn inject_allocator_crate(&mut self, krate
: &ast
::Crate
) {
810 self.cstore
.has_global_allocator
= match &*global_allocator_spans(&self.sess
, krate
) {
811 [span1
, span2
, ..] => {
813 .struct_span_err(*span2
, "cannot define multiple global allocators")
814 .span_label(*span2
, "cannot define a new global allocator")
815 .span_label(*span1
, "previous global allocator defined here")
819 spans
=> !spans
.is_empty(),
822 // Check to see if we actually need an allocator. This desire comes
823 // about through the `#![needs_allocator]` attribute and is typically
824 // written down in liballoc.
825 let mut needs_allocator
= self.sess
.contains_name(&krate
.attrs
, sym
::needs_allocator
);
826 self.cstore
.iter_crate_data(|_
, data
| {
827 needs_allocator
= needs_allocator
|| data
.needs_allocator();
829 if !needs_allocator
{
833 // At this point we've determined that we need an allocator. Let's see
834 // if our compilation session actually needs an allocator based on what
836 let all_rlib
= self.sess
.crate_types().iter().all(|ct
| matches
!(*ct
, CrateType
::Rlib
));
841 // Ok, we need an allocator. Not only that but we're actually going to
842 // create an artifact that needs one linked in. Let's go find the one
843 // that we're going to link in.
845 // First up we check for global allocators. Look at the crate graph here
846 // and see what's a global allocator, including if we ourselves are a
848 let mut global_allocator
=
849 self.cstore
.has_global_allocator
.then(|| Symbol
::intern("this crate"));
850 self.cstore
.iter_crate_data(|_
, data
| {
851 if !data
.has_global_allocator() {
854 match global_allocator
{
855 Some(other_crate
) => {
856 self.sess
.err(&format
!(
857 "the `#[global_allocator]` in {} \
858 conflicts with global \
864 None
=> global_allocator
= Some(data
.name()),
867 if global_allocator
.is_some() {
868 self.cstore
.allocator_kind
= Some(AllocatorKind
::Global
);
872 // Ok we haven't found a global allocator but we still need an
873 // allocator. At this point our allocator request is typically fulfilled
874 // by the standard library, denoted by the `#![default_lib_allocator]`
876 let mut has_default
= self.sess
.contains_name(&krate
.attrs
, sym
::default_lib_allocator
);
877 self.cstore
.iter_crate_data(|_
, data
| {
878 if data
.has_default_lib_allocator() {
885 "no global memory allocator found but one is \
886 required; link to std or \
887 add `#[global_allocator]` to a static item \
888 that implements the GlobalAlloc trait.",
891 self.cstore
.allocator_kind
= Some(AllocatorKind
::Default
);
894 fn inject_dependency_if(
898 needs_dep
: &dyn Fn(&CrateMetadata
) -> bool
,
900 // don't perform this validation if the session has errors, as one of
901 // those errors may indicate a circular dependency which could cause
902 // this to stack overflow.
903 if self.sess
.has_errors() {
907 // Before we inject any dependencies, make sure we don't inject a
908 // circular dependency by validating that this crate doesn't
909 // transitively depend on any crates satisfying `needs_dep`.
910 for dep
in self.cstore
.crate_dependencies_in_reverse_postorder(krate
) {
911 let data
= self.cstore
.get_crate_data(dep
);
912 if needs_dep(&data
) {
913 self.sess
.err(&format
!(
914 "the crate `{}` cannot depend \
915 on a crate that needs {}, but \
917 self.cstore
.get_crate_data(krate
).name(),
924 // All crates satisfying `needs_dep` do not explicitly depend on the
925 // crate provided for this compile, but in order for this compilation to
926 // be successfully linked we need to inject a dependency (to order the
927 // crates on the command line correctly).
928 self.cstore
.iter_crate_data(|cnum
, data
| {
929 if !needs_dep(data
) {
933 info
!("injecting a dep from {} to {}", cnum
, krate
);
934 data
.add_dependency(krate
);
938 fn report_unused_deps(&mut self, krate
: &ast
::Crate
) {
939 // Make a point span rather than covering the whole file
940 let span
= krate
.span
.shrink_to_lo();
941 // Complain about anything left over
942 for (name
, entry
) in self.sess
.opts
.externs
.iter() {
943 if let ExternLocation
::FoundInLibrarySearchDirectories
= entry
.location
{
944 // Don't worry about pathless `--extern foo` sysroot references
947 let name_interned
= Symbol
::intern(name
);
948 if self.used_extern_options
.contains(&name_interned
) {
952 // Got a real unused --extern
953 if self.sess
.opts
.json_unused_externs
{
954 self.cstore
.unused_externs
.push(name_interned
);
958 let diag
= match self.sess
.opts
.extern_dep_specs
.get(name
) {
959 Some(loc
) => BuiltinLintDiagnostics
::ExternDepSpec(name
.clone(), loc
.into()),
961 // If we don't have a specific location, provide a json encoding of the `--extern`
963 let meta
: BTreeMap
<String
, String
> =
964 std
::iter
::once(("name".to_string(), name
.to_string())).collect();
965 BuiltinLintDiagnostics
::ExternDepSpec(
967 ExternDepSpec
::Json(meta
.to_json()),
971 self.sess
.parse_sess
.buffer_lint_with_diagnostic(
972 lint
::builtin
::UNUSED_CRATE_DEPENDENCIES
,
976 "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
978 self.local_crate_name
,
985 pub fn postprocess(&mut self, krate
: &ast
::Crate
) {
986 self.inject_profiler_runtime(krate
);
987 self.inject_allocator_crate(krate
);
988 self.inject_panic_runtime(krate
);
990 self.report_unused_deps(krate
);
992 info
!("{:?}", CrateDump(&self.cstore
));
995 pub fn process_extern_crate(
998 definitions
: &Definitions
,
1002 ast
::ItemKind
::ExternCrate(orig_name
) => {
1004 "resolving extern crate stmt. ident: {} orig_name: {:?}",
1005 item
.ident
, orig_name
1007 let name
= match orig_name
{
1008 Some(orig_name
) => {
1009 validate_crate_name(self.sess
, &orig_name
.as_str(), Some(item
.span
));
1012 None
=> item
.ident
.name
,
1014 let dep_kind
= if self.sess
.contains_name(&item
.attrs
, sym
::no_link
) {
1015 CrateDepKind
::MacrosOnly
1017 CrateDepKind
::Explicit
1020 let cnum
= self.resolve_crate(name
, item
.span
, dep_kind
, None
);
1022 let path_len
= definitions
.def_path(def_id
).data
.len();
1023 self.update_extern_crate(
1026 src
: ExternCrateSource
::Extern(def_id
.to_def_id()),
1029 dependency_of
: LOCAL_CRATE
,
1038 pub fn process_path_extern(&mut self, name
: Symbol
, span
: Span
) -> CrateNum
{
1039 let cnum
= self.resolve_crate(name
, span
, CrateDepKind
::Explicit
, None
);
1041 self.update_extern_crate(
1044 src
: ExternCrateSource
::Path
,
1046 // to have the least priority in `update_extern_crate`
1047 path_len
: usize::MAX
,
1048 dependency_of
: LOCAL_CRATE
,
1055 pub fn maybe_process_path_extern(&mut self, name
: Symbol
) -> Option
<CrateNum
> {
1056 self.maybe_resolve_crate(name
, CrateDepKind
::Explicit
, None
).ok()
1060 fn global_allocator_spans(sess
: &Session
, krate
: &ast
::Crate
) -> Vec
<Span
> {
1066 impl<'ast
, 'a
> visit
::Visitor
<'ast
> for Finder
<'a
> {
1067 fn visit_item(&mut self, item
: &'ast ast
::Item
) {
1068 if item
.ident
.name
== self.name
1069 && self.sess
.contains_name(&item
.attrs
, sym
::rustc_std_internal_symbol
)
1071 self.spans
.push(item
.span
);
1073 visit
::walk_item(self, item
)
1077 let name
= Symbol
::intern(&AllocatorKind
::Global
.fn_name(sym
::alloc
));
1078 let mut f
= Finder { sess, name, spans: Vec::new() }
;
1079 visit
::walk_crate(&mut f
, krate
);