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