]> git.lizzy.rs Git - rust.git/blob - src/librustc_metadata/creader.rs
add CStore::item_generics_num_lifetimes
[rust.git] / src / librustc_metadata / creader.rs
1 //! Validates all used crates and extern libraries and loads their metadata
2
3 use crate::locator::{CrateLocator, CratePaths};
4 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
5
6 use rustc::hir::map::Definitions;
7 use rustc::middle::cstore::DepKind;
8 use rustc::middle::cstore::{CrateSource, ExternCrate, ExternCrateSource, MetadataLoaderDyn};
9 use rustc::session::config::{self, Sanitizer};
10 use rustc::session::search_paths::PathKind;
11 use rustc::session::{CrateDisambiguator, Session};
12 use rustc::ty::TyCtxt;
13 use rustc_data_structures::svh::Svh;
14 use rustc_data_structures::sync::Lrc;
15 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
16 use rustc_index::vec::IndexVec;
17 use rustc_target::spec::{PanicStrategy, TargetTriple};
18
19 use std::path::Path;
20 use std::{cmp, fs};
21
22 use errors::struct_span_err;
23 use log::{debug, info, log_enabled};
24 use proc_macro::bridge::client::ProcMacro;
25 use rustc_expand::base::SyntaxExtension;
26 use rustc_span::edition::Edition;
27 use rustc_span::symbol::{sym, Symbol};
28 use rustc_span::{Span, DUMMY_SP};
29 use syntax::ast;
30 use syntax::attr;
31 use syntax::expand::allocator::{global_allocator_spans, AllocatorKind};
32
33 use rustc_error_codes::*;
34
35 #[derive(Clone)]
36 pub struct CStore {
37     metas: IndexVec<CrateNum, Option<Lrc<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 has a `#[global_allocator]` item.
43     has_global_allocator: bool,
44 }
45
46 pub struct CrateLoader<'a> {
47     // Immutable configuration.
48     sess: &'a Session,
49     metadata_loader: &'a MetadataLoaderDyn,
50     local_crate_name: Symbol,
51     // Mutable output.
52     cstore: CStore,
53 }
54
55 pub enum LoadedMacro {
56     MacroDef(ast::Item, Edition),
57     ProcMacro(SyntaxExtension),
58 }
59
60 crate struct Library {
61     pub source: CrateSource,
62     pub metadata: MetadataBlob,
63 }
64
65 enum LoadResult {
66     Previous(CrateNum),
67     Loaded(Library),
68 }
69
70 enum LoadError<'a> {
71     LocatorError(CrateLocator<'a>),
72 }
73
74 impl<'a> LoadError<'a> {
75     fn report(self) -> ! {
76         match self {
77             LoadError::LocatorError(locator) => locator.report_errs(),
78         }
79     }
80 }
81
82 fn dump_crates(cstore: &CStore) {
83     info!("resolved crates:");
84     cstore.iter_crate_data(|cnum, data| {
85         info!("  name: {}", data.name());
86         info!("  cnum: {}", cnum);
87         info!("  hash: {}", data.hash());
88         info!("  reqd: {:?}", data.dep_kind());
89         let CrateSource { dylib, rlib, rmeta } = data.source();
90         dylib.as_ref().map(|dl| info!("  dylib: {}", dl.0.display()));
91         rlib.as_ref().map(|rl| info!("   rlib: {}", rl.0.display()));
92         rmeta.as_ref().map(|rl| info!("   rmeta: {}", rl.0.display()));
93     });
94 }
95
96 impl CStore {
97     crate fn from_tcx(tcx: TyCtxt<'_>) -> &CStore {
98         tcx.cstore_as_any().downcast_ref::<CStore>().expect("`tcx.cstore` is not a `CStore`")
99     }
100
101     fn alloc_new_crate_num(&mut self) -> CrateNum {
102         self.metas.push(None);
103         CrateNum::new(self.metas.len() - 1)
104     }
105
106     crate fn get_crate_data(&self, cnum: CrateNum) -> &CrateMetadata {
107         self.metas[cnum]
108             .as_ref()
109             .unwrap_or_else(|| panic!("Failed to get crate data for {:?}", cnum))
110     }
111
112     fn set_crate_data(&mut self, cnum: CrateNum, data: CrateMetadata) {
113         assert!(self.metas[cnum].is_none(), "Overwriting crate metadata entry");
114         self.metas[cnum] = Some(Lrc::new(data));
115     }
116
117     crate fn iter_crate_data(&self, mut f: impl FnMut(CrateNum, &CrateMetadata)) {
118         for (cnum, data) in self.metas.iter_enumerated() {
119             if let Some(data) = data {
120                 f(cnum, data);
121             }
122         }
123     }
124
125     fn push_dependencies_in_postorder(&self, deps: &mut Vec<CrateNum>, cnum: CrateNum) {
126         if !deps.contains(&cnum) {
127             let data = self.get_crate_data(cnum);
128             for &dep in data.dependencies().iter() {
129                 if dep != cnum {
130                     self.push_dependencies_in_postorder(deps, dep);
131                 }
132             }
133
134             deps.push(cnum);
135         }
136     }
137
138     crate fn crate_dependencies_in_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
139         let mut deps = Vec::new();
140         if cnum == LOCAL_CRATE {
141             self.iter_crate_data(|cnum, _| self.push_dependencies_in_postorder(&mut deps, cnum));
142         } else {
143             self.push_dependencies_in_postorder(&mut deps, cnum);
144         }
145         deps
146     }
147
148     fn crate_dependencies_in_reverse_postorder(&self, cnum: CrateNum) -> Vec<CrateNum> {
149         let mut deps = self.crate_dependencies_in_postorder(cnum);
150         deps.reverse();
151         deps
152     }
153
154     crate fn injected_panic_runtime(&self) -> Option<CrateNum> {
155         self.injected_panic_runtime
156     }
157
158     crate fn allocator_kind(&self) -> Option<AllocatorKind> {
159         self.allocator_kind
160     }
161
162     crate fn has_global_allocator(&self) -> bool {
163         self.has_global_allocator
164     }
165 }
166
167 impl<'a> CrateLoader<'a> {
168     pub fn new(
169         sess: &'a Session,
170         metadata_loader: &'a MetadataLoaderDyn,
171         local_crate_name: &str,
172     ) -> Self {
173         CrateLoader {
174             sess,
175             metadata_loader,
176             local_crate_name: Symbol::intern(local_crate_name),
177             cstore: CStore {
178                 // We add an empty entry for LOCAL_CRATE (which maps to zero) in
179                 // order to make array indices in `metas` match with the
180                 // corresponding `CrateNum`. This first entry will always remain
181                 // `None`.
182                 metas: IndexVec::from_elem_n(None, 1),
183                 injected_panic_runtime: None,
184                 allocator_kind: None,
185                 has_global_allocator: false,
186             },
187         }
188     }
189
190     pub fn cstore(&self) -> &CStore {
191         &self.cstore
192     }
193
194     pub fn into_cstore(self) -> CStore {
195         self.cstore
196     }
197
198     fn existing_match(&self, name: Symbol, hash: Option<Svh>, kind: PathKind) -> Option<CrateNum> {
199         let mut ret = None;
200         self.cstore.iter_crate_data(|cnum, data| {
201             if data.name() != name {
202                 return;
203             }
204
205             match hash {
206                 Some(hash) if hash == data.hash() => {
207                     ret = Some(cnum);
208                     return;
209                 }
210                 Some(..) => return,
211                 None => {}
212             }
213
214             // When the hash is None we're dealing with a top-level dependency
215             // in which case we may have a specification on the command line for
216             // this library. Even though an upstream library may have loaded
217             // something of the same name, we have to make sure it was loaded
218             // from the exact same location as well.
219             //
220             // We're also sure to compare *paths*, not actual byte slices. The
221             // `source` stores paths which are normalized which may be different
222             // from the strings on the command line.
223             let source = self.cstore.get_crate_data(cnum).source();
224             if let Some(entry) = self.sess.opts.externs.get(&name.as_str()) {
225                 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
226                 if let Some(mut files) = entry.files() {
227                     if files.any(|l| {
228                         let l = fs::canonicalize(l).ok();
229                         source.dylib.as_ref().map(|p| &p.0) == l.as_ref()
230                             || source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
231                     }) {
232                         ret = Some(cnum);
233                     }
234                 }
235                 return;
236             }
237
238             // Alright, so we've gotten this far which means that `data` has the
239             // right name, we don't have a hash, and we don't have a --extern
240             // pointing for ourselves. We're still not quite yet done because we
241             // have to make sure that this crate was found in the crate lookup
242             // path (this is a top-level dependency) as we don't want to
243             // implicitly load anything inside the dependency lookup path.
244             let prev_kind = source
245                 .dylib
246                 .as_ref()
247                 .or(source.rlib.as_ref())
248                 .or(source.rmeta.as_ref())
249                 .expect("No sources for crate")
250                 .1;
251             if kind.matches(prev_kind) {
252                 ret = Some(cnum);
253             }
254         });
255         return ret;
256     }
257
258     fn verify_no_symbol_conflicts(&self, span: Span, root: &CrateRoot<'_>) {
259         // Check for (potential) conflicts with the local crate
260         if self.local_crate_name == root.name()
261             && self.sess.local_crate_disambiguator() == root.disambiguator()
262         {
263             struct_span_err!(
264                 self.sess,
265                 span,
266                 E0519,
267                 "the current crate is indistinguishable from one of its \
268                          dependencies: it has the same crate-name `{}` and was \
269                          compiled with the same `-C metadata` arguments. This \
270                          will result in symbol conflicts between the two.",
271                 root.name()
272             )
273             .emit()
274         }
275
276         // Check for conflicts with any crate loaded so far
277         self.cstore.iter_crate_data(|_, other| {
278             if other.name() == root.name() && // same crate-name
279                other.disambiguator() == root.disambiguator() &&  // same crate-disambiguator
280                other.hash() != root.hash()
281             {
282                 // but different SVH
283                 struct_span_err!(
284                     self.sess,
285                     span,
286                     E0523,
287                     "found two different crates with name `{}` that are \
288                          not distinguished by differing `-C metadata`. This \
289                          will result in symbol conflicts between the two.",
290                     root.name()
291                 )
292                 .emit();
293             }
294         });
295     }
296
297     fn register_crate(
298         &mut self,
299         host_lib: Option<Library>,
300         root: Option<&CratePaths>,
301         span: Span,
302         lib: Library,
303         dep_kind: DepKind,
304         name: Symbol,
305     ) -> CrateNum {
306         let _prof_timer = self.sess.prof.generic_activity("metadata_register_crate");
307
308         let Library { source, metadata } = lib;
309         let crate_root = metadata.get_root();
310         let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
311         self.verify_no_symbol_conflicts(span, &crate_root);
312
313         let private_dep =
314             self.sess.opts.externs.get(&name.as_str()).map(|e| e.is_private_dep).unwrap_or(false);
315
316         info!("register crate `{}` (private_dep = {})", crate_root.name(), private_dep);
317
318         // Claim this crate number and cache it
319         let cnum = self.cstore.alloc_new_crate_num();
320
321         // Maintain a reference to the top most crate.
322         // Stash paths for top-most crate locally if necessary.
323         let crate_paths;
324         let root = if let Some(root) = root {
325             root
326         } else {
327             crate_paths = CratePaths::new(crate_root.name(), source.clone());
328             &crate_paths
329         };
330
331         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
332
333         let raw_proc_macros = if crate_root.is_proc_macro_crate() {
334             let temp_root;
335             let (dlsym_source, dlsym_root) = match &host_lib {
336                 Some(host_lib) => (&host_lib.source, {
337                     temp_root = host_lib.metadata.get_root();
338                     &temp_root
339                 }),
340                 None => (&source, &crate_root),
341             };
342             let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
343             Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator(), span))
344         } else {
345             None
346         };
347
348         self.cstore.set_crate_data(
349             cnum,
350             CrateMetadata::new(
351                 self.sess,
352                 metadata,
353                 crate_root,
354                 raw_proc_macros,
355                 cnum,
356                 cnum_map,
357                 dep_kind,
358                 source,
359                 private_dep,
360                 host_hash,
361             ),
362         );
363
364         cnum
365     }
366
367     fn load_proc_macro<'b>(
368         &self,
369         locator: &mut CrateLocator<'b>,
370         path_kind: PathKind,
371     ) -> Option<(LoadResult, Option<Library>)>
372     where
373         'a: 'b,
374     {
375         // Use a new crate locator so trying to load a proc macro doesn't affect the error
376         // message we emit
377         let mut proc_macro_locator = locator.clone();
378
379         // Try to load a proc macro
380         proc_macro_locator.is_proc_macro = Some(true);
381
382         // Load the proc macro crate for the target
383         let (locator, target_result) = if self.sess.opts.debugging_opts.dual_proc_macros {
384             proc_macro_locator.reset();
385             let result = match self.load(&mut proc_macro_locator)? {
386                 LoadResult::Previous(cnum) => return Some((LoadResult::Previous(cnum), None)),
387                 LoadResult::Loaded(library) => Some(LoadResult::Loaded(library)),
388             };
389             locator.hash = locator.host_hash;
390             // Use the locator when looking for the host proc macro crate, as that is required
391             // so we want it to affect the error message
392             (locator, result)
393         } else {
394             (&mut proc_macro_locator, None)
395         };
396
397         // Load the proc macro crate for the host
398
399         locator.reset();
400         locator.is_proc_macro = Some(true);
401         locator.target = &self.sess.host;
402         locator.triple = TargetTriple::from_triple(config::host_triple());
403         locator.filesearch = self.sess.host_filesearch(path_kind);
404
405         let host_result = self.load(locator)?;
406
407         Some(if self.sess.opts.debugging_opts.dual_proc_macros {
408             let host_result = match host_result {
409                 LoadResult::Previous(..) => {
410                     panic!("host and target proc macros must be loaded in lock-step")
411                 }
412                 LoadResult::Loaded(library) => library,
413             };
414             (target_result.unwrap(), Some(host_result))
415         } else {
416             (host_result, None)
417         })
418     }
419
420     fn resolve_crate<'b>(
421         &'b mut self,
422         name: Symbol,
423         span: Span,
424         dep_kind: DepKind,
425         dep: Option<(&'b CratePaths, &'b CrateDep)>,
426     ) -> CrateNum {
427         self.maybe_resolve_crate(name, span, dep_kind, dep).unwrap_or_else(|err| err.report())
428     }
429
430     fn maybe_resolve_crate<'b>(
431         &'b mut self,
432         name: Symbol,
433         span: Span,
434         mut dep_kind: DepKind,
435         dep: Option<(&'b CratePaths, &'b CrateDep)>,
436     ) -> Result<CrateNum, LoadError<'b>> {
437         info!("resolving crate `{}`", name);
438         let (root, hash, host_hash, extra_filename, path_kind) = match dep {
439             Some((root, dep)) => (
440                 Some(root),
441                 Some(dep.hash),
442                 dep.host_hash,
443                 Some(&dep.extra_filename[..]),
444                 PathKind::Dependency,
445             ),
446             None => (None, None, None, None, PathKind::Crate),
447         };
448         let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) {
449             (LoadResult::Previous(cnum), None)
450         } else {
451             info!("falling back to a load");
452             let mut locator = CrateLocator::new(
453                 self.sess,
454                 self.metadata_loader,
455                 name,
456                 hash,
457                 host_hash,
458                 extra_filename,
459                 false, // is_host
460                 path_kind,
461                 span,
462                 root,
463                 Some(false), // is_proc_macro
464             );
465
466             self.load(&mut locator)
467                 .map(|r| (r, None))
468                 .or_else(|| {
469                     dep_kind = DepKind::UnexportedMacrosOnly;
470                     self.load_proc_macro(&mut locator, path_kind)
471                 })
472                 .ok_or_else(move || LoadError::LocatorError(locator))?
473         };
474
475         match result {
476             (LoadResult::Previous(cnum), None) => {
477                 let data = self.cstore.get_crate_data(cnum);
478                 if data.is_proc_macro_crate() {
479                     dep_kind = DepKind::UnexportedMacrosOnly;
480                 }
481                 data.update_dep_kind(|data_dep_kind| cmp::max(data_dep_kind, dep_kind));
482                 Ok(cnum)
483             }
484             (LoadResult::Loaded(library), host_library) => {
485                 Ok(self.register_crate(host_library, root, span, library, dep_kind, name))
486             }
487             _ => panic!(),
488         }
489     }
490
491     fn load(&self, locator: &mut CrateLocator<'_>) -> Option<LoadResult> {
492         let library = locator.maybe_load_library_crate()?;
493
494         // In the case that we're loading a crate, but not matching
495         // against a hash, we could load a crate which has the same hash
496         // as an already loaded crate. If this is the case prevent
497         // duplicates by just using the first crate.
498         //
499         // Note that we only do this for target triple crates, though, as we
500         // don't want to match a host crate against an equivalent target one
501         // already loaded.
502         let root = library.metadata.get_root();
503         if locator.triple == self.sess.opts.target_triple {
504             let mut result = LoadResult::Loaded(library);
505             self.cstore.iter_crate_data(|cnum, data| {
506                 if data.name() == root.name() && root.hash() == data.hash() {
507                     assert!(locator.hash.is_none());
508                     info!("load success, going to previous cnum: {}", cnum);
509                     result = LoadResult::Previous(cnum);
510                 }
511             });
512             Some(result)
513         } else {
514             Some(LoadResult::Loaded(library))
515         }
516     }
517
518     fn update_extern_crate(&self, cnum: CrateNum, extern_crate: ExternCrate) {
519         let cmeta = self.cstore.get_crate_data(cnum);
520         if cmeta.update_extern_crate(extern_crate) {
521             // Propagate the extern crate info to dependencies if it was updated.
522             let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
523             for &dep_cnum in cmeta.dependencies().iter() {
524                 self.update_extern_crate(dep_cnum, extern_crate);
525             }
526         }
527     }
528
529     // Go through the crate metadata and load any crates that it references
530     fn resolve_crate_deps(
531         &mut self,
532         root: &CratePaths,
533         crate_root: &CrateRoot<'_>,
534         metadata: &MetadataBlob,
535         krate: CrateNum,
536         span: Span,
537         dep_kind: DepKind,
538     ) -> CrateNumMap {
539         debug!("resolving deps of external crate");
540         if crate_root.is_proc_macro_crate() {
541             return CrateNumMap::new();
542         }
543
544         // The map from crate numbers in the crate we're resolving to local crate numbers.
545         // We map 0 and all other holes in the map to our parent crate. The "additional"
546         // self-dependencies should be harmless.
547         std::iter::once(krate)
548             .chain(crate_root.decode_crate_deps(metadata).map(|dep| {
549                 info!(
550                     "resolving dep crate {} hash: `{}` extra filename: `{}`",
551                     dep.name, dep.hash, dep.extra_filename
552                 );
553                 if dep.kind == DepKind::UnexportedMacrosOnly {
554                     return krate;
555                 }
556                 let dep_kind = match dep_kind {
557                     DepKind::MacrosOnly => DepKind::MacrosOnly,
558                     _ => dep.kind,
559                 };
560                 self.resolve_crate(dep.name, span, dep_kind, Some((root, &dep)))
561             }))
562             .collect()
563     }
564
565     fn dlsym_proc_macros(
566         &self,
567         path: &Path,
568         disambiguator: CrateDisambiguator,
569         span: Span,
570     ) -> &'static [ProcMacro] {
571         use crate::dynamic_lib::DynamicLibrary;
572         use std::env;
573
574         // Make sure the path contains a / or the linker will search for it.
575         let path = env::current_dir().unwrap().join(path);
576         let lib = match DynamicLibrary::open(Some(&path)) {
577             Ok(lib) => lib,
578             Err(err) => self.sess.span_fatal(span, &err),
579         };
580
581         let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator);
582         let decls = unsafe {
583             let sym = match lib.symbol(&sym) {
584                 Ok(f) => f,
585                 Err(err) => self.sess.span_fatal(span, &err),
586             };
587             *(sym as *const &[ProcMacro])
588         };
589
590         // Intentionally leak the dynamic library. We can't ever unload it
591         // since the library can make things that will live arbitrarily long.
592         std::mem::forget(lib);
593
594         decls
595     }
596
597     fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
598         // If we're only compiling an rlib, then there's no need to select a
599         // panic runtime, so we just skip this section entirely.
600         let any_non_rlib =
601             self.sess.crate_types.borrow().iter().any(|ct| *ct != config::CrateType::Rlib);
602         if !any_non_rlib {
603             info!("panic runtime injection skipped, only generating rlib");
604             return;
605         }
606
607         // If we need a panic runtime, we try to find an existing one here. At
608         // the same time we perform some general validation of the DAG we've got
609         // going such as ensuring everything has a compatible panic strategy.
610         //
611         // The logic for finding the panic runtime here is pretty much the same
612         // as the allocator case with the only addition that the panic strategy
613         // compilation mode also comes into play.
614         let desired_strategy = self.sess.panic_strategy();
615         let mut runtime_found = false;
616         let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
617
618         self.cstore.iter_crate_data(|cnum, data| {
619             needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
620             if data.is_panic_runtime() {
621                 // Inject a dependency from all #![needs_panic_runtime] to this
622                 // #![panic_runtime] crate.
623                 self.inject_dependency_if(cnum, "a panic runtime", &|data| {
624                     data.needs_panic_runtime()
625                 });
626                 runtime_found = runtime_found || data.dep_kind() == DepKind::Explicit;
627             }
628         });
629
630         // If an explicitly linked and matching panic runtime was found, or if
631         // we just don't need one at all, then we're done here and there's
632         // nothing else to do.
633         if !needs_panic_runtime || runtime_found {
634             return;
635         }
636
637         // By this point we know that we (a) need a panic runtime and (b) no
638         // panic runtime was explicitly linked. Here we just load an appropriate
639         // default runtime for our panic strategy and then inject the
640         // dependencies.
641         //
642         // We may resolve to an already loaded crate (as the crate may not have
643         // been explicitly linked prior to this) and we may re-inject
644         // dependencies again, but both of those situations are fine.
645         //
646         // Also note that we have yet to perform validation of the crate graph
647         // in terms of everyone has a compatible panic runtime format, that's
648         // performed later as part of the `dependency_format` module.
649         let name = match desired_strategy {
650             PanicStrategy::Unwind => Symbol::intern("panic_unwind"),
651             PanicStrategy::Abort => Symbol::intern("panic_abort"),
652         };
653         info!("panic runtime not found -- loading {}", name);
654
655         let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None);
656         let data = self.cstore.get_crate_data(cnum);
657
658         // Sanity check the loaded crate to ensure it is indeed a panic runtime
659         // and the panic strategy is indeed what we thought it was.
660         if !data.is_panic_runtime() {
661             self.sess.err(&format!("the crate `{}` is not a panic runtime", name));
662         }
663         if data.panic_strategy() != desired_strategy {
664             self.sess.err(&format!(
665                 "the crate `{}` does not have the panic \
666                                     strategy `{}`",
667                 name,
668                 desired_strategy.desc()
669             ));
670         }
671
672         self.cstore.injected_panic_runtime = Some(cnum);
673         self.inject_dependency_if(cnum, "a panic runtime", &|data| data.needs_panic_runtime());
674     }
675
676     fn inject_sanitizer_runtime(&mut self) {
677         if let Some(ref sanitizer) = self.sess.opts.debugging_opts.sanitizer {
678             // Sanitizers can only be used on some tested platforms with
679             // executables linked to `std`
680             const ASAN_SUPPORTED_TARGETS: &[&str] =
681                 &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
682             const TSAN_SUPPORTED_TARGETS: &[&str] =
683                 &["x86_64-unknown-linux-gnu", "x86_64-apple-darwin"];
684             const LSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
685             const MSAN_SUPPORTED_TARGETS: &[&str] = &["x86_64-unknown-linux-gnu"];
686
687             let supported_targets = match *sanitizer {
688                 Sanitizer::Address => ASAN_SUPPORTED_TARGETS,
689                 Sanitizer::Thread => TSAN_SUPPORTED_TARGETS,
690                 Sanitizer::Leak => LSAN_SUPPORTED_TARGETS,
691                 Sanitizer::Memory => MSAN_SUPPORTED_TARGETS,
692             };
693             if !supported_targets.contains(&&*self.sess.opts.target_triple.triple()) {
694                 self.sess.err(&format!(
695                     "{:?}Sanitizer only works with the `{}` target",
696                     sanitizer,
697                     supported_targets.join("` or `")
698                 ));
699                 return;
700             }
701
702             // firstyear 2017 - during testing I was unable to access an OSX machine
703             // to make this work on different crate types. As a result, today I have
704             // only been able to test and support linux as a target.
705             if self.sess.opts.target_triple.triple() == "x86_64-unknown-linux-gnu" {
706                 if !self.sess.crate_types.borrow().iter().all(|ct| {
707                     match *ct {
708                         // Link the runtime
709                         config::CrateType::Executable => true,
710                         // This crate will be compiled with the required
711                         // instrumentation pass
712                         config::CrateType::Staticlib
713                         | config::CrateType::Rlib
714                         | config::CrateType::Dylib
715                         | config::CrateType::Cdylib => false,
716                         _ => {
717                             self.sess.err(&format!(
718                                 "Only executables, staticlibs, \
719                                 cdylibs, dylibs and rlibs can be compiled with \
720                                 `-Z sanitizer`"
721                             ));
722                             false
723                         }
724                     }
725                 }) {
726                     return;
727                 }
728             } else {
729                 if !self.sess.crate_types.borrow().iter().all(|ct| {
730                     match *ct {
731                         // Link the runtime
732                         config::CrateType::Executable => true,
733                         // This crate will be compiled with the required
734                         // instrumentation pass
735                         config::CrateType::Rlib => false,
736                         _ => {
737                             self.sess.err(&format!(
738                                 "Only executables and rlibs can be \
739                                                     compiled with `-Z sanitizer`"
740                             ));
741                             false
742                         }
743                     }
744                 }) {
745                     return;
746                 }
747             }
748
749             let mut uses_std = false;
750             self.cstore.iter_crate_data(|_, data| {
751                 if data.name() == sym::std {
752                     uses_std = true;
753                 }
754             });
755
756             if uses_std {
757                 let name = Symbol::intern(match sanitizer {
758                     Sanitizer::Address => "rustc_asan",
759                     Sanitizer::Leak => "rustc_lsan",
760                     Sanitizer::Memory => "rustc_msan",
761                     Sanitizer::Thread => "rustc_tsan",
762                 });
763                 info!("loading sanitizer: {}", name);
764
765                 let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Explicit, None);
766                 let data = self.cstore.get_crate_data(cnum);
767
768                 // Sanity check the loaded crate to ensure it is indeed a sanitizer runtime
769                 if !data.is_sanitizer_runtime() {
770                     self.sess.err(&format!("the crate `{}` is not a sanitizer runtime", name));
771                 }
772             } else {
773                 self.sess.err("Must link std to be compiled with `-Z sanitizer`");
774             }
775         }
776     }
777
778     fn inject_profiler_runtime(&mut self) {
779         if self.sess.opts.debugging_opts.profile || self.sess.opts.cg.profile_generate.enabled() {
780             info!("loading profiler");
781
782             let name = Symbol::intern("profiler_builtins");
783             let cnum = self.resolve_crate(name, DUMMY_SP, DepKind::Implicit, None);
784             let data = self.cstore.get_crate_data(cnum);
785
786             // Sanity check the loaded crate to ensure it is indeed a profiler runtime
787             if !data.is_profiler_runtime() {
788                 self.sess.err(&format!(
789                     "the crate `profiler_builtins` is not \
790                                         a profiler runtime"
791                 ));
792             }
793         }
794     }
795
796     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
797         self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
798             [span1, span2, ..] => {
799                 self.sess
800                     .struct_span_err(*span2, "cannot define multiple global allocators")
801                     .span_label(*span2, "cannot define a new global allocator")
802                     .span_label(*span1, "previous global allocator is defined here")
803                     .emit();
804                 true
805             }
806             spans => !spans.is_empty(),
807         };
808
809         // Check to see if we actually need an allocator. This desire comes
810         // about through the `#![needs_allocator]` attribute and is typically
811         // written down in liballoc.
812         let mut needs_allocator = attr::contains_name(&krate.attrs, sym::needs_allocator);
813         self.cstore.iter_crate_data(|_, data| {
814             needs_allocator = needs_allocator || data.needs_allocator();
815         });
816         if !needs_allocator {
817             return;
818         }
819
820         // At this point we've determined that we need an allocator. Let's see
821         // if our compilation session actually needs an allocator based on what
822         // we're emitting.
823         let all_rlib = self.sess.crate_types.borrow().iter().all(|ct| match *ct {
824             config::CrateType::Rlib => true,
825             _ => false,
826         });
827         if all_rlib {
828             return;
829         }
830
831         // Ok, we need an allocator. Not only that but we're actually going to
832         // create an artifact that needs one linked in. Let's go find the one
833         // that we're going to link in.
834         //
835         // First up we check for global allocators. Look at the crate graph here
836         // and see what's a global allocator, including if we ourselves are a
837         // global allocator.
838         let mut global_allocator =
839             self.cstore.has_global_allocator.then(|| Symbol::intern("this crate"));
840         self.cstore.iter_crate_data(|_, data| {
841             if !data.has_global_allocator() {
842                 return;
843             }
844             match global_allocator {
845                 Some(other_crate) => {
846                     self.sess.err(&format!(
847                         "the `#[global_allocator]` in {} \
848                                             conflicts with global \
849                                             allocator in: {}",
850                         other_crate,
851                         data.name()
852                     ));
853                 }
854                 None => global_allocator = Some(data.name()),
855             }
856         });
857         if global_allocator.is_some() {
858             self.cstore.allocator_kind = Some(AllocatorKind::Global);
859             return;
860         }
861
862         // Ok we haven't found a global allocator but we still need an
863         // allocator. At this point our allocator request is typically fulfilled
864         // by the standard library, denoted by the `#![default_lib_allocator]`
865         // attribute.
866         let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator);
867         self.cstore.iter_crate_data(|_, data| {
868             if data.has_default_lib_allocator() {
869                 has_default = true;
870             }
871         });
872
873         if !has_default {
874             self.sess.err(
875                 "no global memory allocator found but one is \
876                            required; link to std or \
877                            add `#[global_allocator]` to a static item \
878                            that implements the GlobalAlloc trait.",
879             );
880         }
881         self.cstore.allocator_kind = Some(AllocatorKind::Default);
882     }
883
884     fn inject_dependency_if(
885         &self,
886         krate: CrateNum,
887         what: &str,
888         needs_dep: &dyn Fn(&CrateMetadata) -> bool,
889     ) {
890         // don't perform this validation if the session has errors, as one of
891         // those errors may indicate a circular dependency which could cause
892         // this to stack overflow.
893         if self.sess.has_errors() {
894             return;
895         }
896
897         // Before we inject any dependencies, make sure we don't inject a
898         // circular dependency by validating that this crate doesn't
899         // transitively depend on any crates satisfying `needs_dep`.
900         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
901             let data = self.cstore.get_crate_data(dep);
902             if needs_dep(&data) {
903                 self.sess.err(&format!(
904                     "the crate `{}` cannot depend \
905                                         on a crate that needs {}, but \
906                                         it depends on `{}`",
907                     self.cstore.get_crate_data(krate).name(),
908                     what,
909                     data.name()
910                 ));
911             }
912         }
913
914         // All crates satisfying `needs_dep` do not explicitly depend on the
915         // crate provided for this compile, but in order for this compilation to
916         // be successfully linked we need to inject a dependency (to order the
917         // crates on the command line correctly).
918         self.cstore.iter_crate_data(|cnum, data| {
919             if !needs_dep(data) {
920                 return;
921             }
922
923             info!("injecting a dep from {} to {}", cnum, krate);
924             data.add_dependency(krate);
925         });
926     }
927
928     pub fn postprocess(&mut self, krate: &ast::Crate) {
929         self.inject_sanitizer_runtime();
930         self.inject_profiler_runtime();
931         self.inject_allocator_crate(krate);
932         self.inject_panic_runtime(krate);
933
934         if log_enabled!(log::Level::Info) {
935             dump_crates(&self.cstore);
936         }
937     }
938
939     pub fn process_extern_crate(
940         &mut self,
941         item: &ast::Item,
942         definitions: &Definitions,
943     ) -> CrateNum {
944         match item.kind {
945             ast::ItemKind::ExternCrate(orig_name) => {
946                 debug!(
947                     "resolving extern crate stmt. ident: {} orig_name: {:?}",
948                     item.ident, orig_name
949                 );
950                 let name = match orig_name {
951                     Some(orig_name) => {
952                         crate::validate_crate_name(
953                             Some(self.sess),
954                             &orig_name.as_str(),
955                             Some(item.span),
956                         );
957                         orig_name
958                     }
959                     None => item.ident.name,
960                 };
961                 let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
962                     DepKind::UnexportedMacrosOnly
963                 } else {
964                     DepKind::Explicit
965                 };
966
967                 let cnum = self.resolve_crate(name, item.span, dep_kind, None);
968
969                 let def_id = definitions.opt_local_def_id(item.id).unwrap();
970                 let path_len = definitions.def_path(def_id.index).data.len();
971                 self.update_extern_crate(
972                     cnum,
973                     ExternCrate {
974                         src: ExternCrateSource::Extern(def_id),
975                         span: item.span,
976                         path_len,
977                         dependency_of: LOCAL_CRATE,
978                     },
979                 );
980                 cnum
981             }
982             _ => bug!(),
983         }
984     }
985
986     pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> CrateNum {
987         let cnum = self.resolve_crate(name, span, DepKind::Explicit, None);
988
989         self.update_extern_crate(
990             cnum,
991             ExternCrate {
992                 src: ExternCrateSource::Path,
993                 span,
994                 // to have the least priority in `update_extern_crate`
995                 path_len: usize::max_value(),
996                 dependency_of: LOCAL_CRATE,
997             },
998         );
999
1000         cnum
1001     }
1002
1003     pub fn maybe_process_path_extern(&mut self, name: Symbol, span: Span) -> Option<CrateNum> {
1004         self.maybe_resolve_crate(name, span, DepKind::Explicit, None).ok()
1005     }
1006 }