]> git.lizzy.rs Git - rust.git/blob - src/librustc/metadata/creader.rs
04f164c296d2e984bda7f52e71ba77d9fa205fd0
[rust.git] / src / librustc / metadata / creader.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_camel_case_types)]
12
13 //! Validates all used crates and extern libraries and loads their metadata
14
15 use back::svh::Svh;
16 use session::{config, Session};
17 use session::search_paths::PathKind;
18 use metadata::common::rustc_version;
19 use metadata::cstore;
20 use metadata::cstore::{CStore, CrateSource, MetadataBlob};
21 use metadata::decoder;
22 use metadata::loader;
23 use metadata::loader::CratePaths;
24 use util::nodemap::FnvHashMap;
25 use front::map as hir_map;
26
27 use std::cell::{RefCell, Cell};
28 use std::path::PathBuf;
29 use std::rc::Rc;
30 use std::fs;
31
32 use syntax::ast;
33 use syntax::abi;
34 use syntax::codemap::{self, Span, mk_sp, Pos};
35 use syntax::parse;
36 use syntax::attr;
37 use syntax::attr::AttrMetaMethods;
38 use syntax::parse::token::InternedString;
39 use syntax::util::small_vector::SmallVector;
40 use rustc_front::visit;
41 use rustc_front::hir;
42 use log;
43
44 pub struct LocalCrateReader<'a, 'b:'a> {
45     sess: &'a Session,
46     creader: CrateReader<'a>,
47     ast_map: &'a hir_map::Map<'b>,
48 }
49
50 pub struct CrateReader<'a> {
51     sess: &'a Session,
52     next_crate_num: ast::CrateNum,
53     foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
54 }
55
56 impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> {
57     fn visit_item(&mut self, a: &hir::Item) {
58         self.process_item(a);
59         visit::walk_item(self, a);
60     }
61 }
62
63 fn dump_crates(cstore: &CStore) {
64     info!("resolved crates:");
65     cstore.iter_crate_data_origins(|_, data, opt_source| {
66         info!("  name: {}", data.name());
67         info!("  cnum: {}", data.cnum);
68         info!("  hash: {}", data.hash());
69         info!("  reqd: {}", data.explicitly_linked.get());
70         opt_source.map(|cs| {
71             let CrateSource { dylib, rlib, cnum: _ } = cs;
72             dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
73             rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
74         });
75     })
76 }
77
78 fn should_link(i: &ast::Item) -> bool {
79     !attr::contains_name(&i.attrs, "no_link")
80 }
81 // Dup for the hir
82 fn should_link_hir(i: &hir::Item) -> bool {
83     !attr::contains_name(&i.attrs, "no_link")
84 }
85
86 struct CrateInfo {
87     ident: String,
88     name: String,
89     id: ast::NodeId,
90     should_link: bool,
91 }
92
93 pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
94     let say = |s: &str| {
95         match (sp, sess) {
96             (_, None) => panic!("{}", s),
97             (Some(sp), Some(sess)) => sess.span_err(sp, s),
98             (None, Some(sess)) => sess.err(s),
99         }
100     };
101     if s.is_empty() {
102         say("crate name must not be empty");
103     }
104     for c in s.chars() {
105         if c.is_alphanumeric() { continue }
106         if c == '_'  { continue }
107         say(&format!("invalid character `{}` in crate name: `{}`", c, s));
108     }
109     match sess {
110         Some(sess) => sess.abort_if_errors(),
111         None => {}
112     }
113 }
114
115
116 fn register_native_lib(sess: &Session,
117                        span: Option<Span>,
118                        name: String,
119                        kind: cstore::NativeLibraryKind) {
120     if name.is_empty() {
121         match span {
122             Some(span) => {
123                 span_err!(sess, span, E0454,
124                           "#[link(name = \"\")] given with empty name");
125             }
126             None => {
127                 sess.err("empty library name given via `-l`");
128             }
129         }
130         return
131     }
132     let is_osx = sess.target.target.options.is_like_osx;
133     if kind == cstore::NativeFramework && !is_osx {
134         let msg = "native frameworks are only available on OSX targets";
135         match span {
136             Some(span) => {
137                 span_err!(sess, span, E0455,
138                           "{}", msg)
139             }
140             None => sess.err(msg),
141         }
142     }
143     sess.cstore.add_used_library(name, kind);
144 }
145
146 // Extra info about a crate loaded for plugins or exported macros.
147 struct ExtensionCrate {
148     metadata: PMDSource,
149     dylib: Option<PathBuf>,
150     target_only: bool,
151 }
152
153 enum PMDSource {
154     Registered(Rc<cstore::crate_metadata>),
155     Owned(MetadataBlob),
156 }
157
158 impl PMDSource {
159     pub fn as_slice<'a>(&'a self) -> &'a [u8] {
160         match *self {
161             PMDSource::Registered(ref cmd) => cmd.data(),
162             PMDSource::Owned(ref mdb) => mdb.as_slice(),
163         }
164     }
165 }
166
167 impl<'a> CrateReader<'a> {
168     pub fn new(sess: &'a Session) -> CrateReader<'a> {
169         CrateReader {
170             sess: sess,
171             next_crate_num: sess.cstore.next_crate_num(),
172             foreign_item_map: FnvHashMap(),
173         }
174     }
175
176     fn extract_crate_info(&self, i: &ast::Item) -> Option<CrateInfo> {
177         match i.node {
178             ast::ItemExternCrate(ref path_opt) => {
179                 debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
180                        i.ident, path_opt);
181                 let name = match *path_opt {
182                     Some(name) => {
183                         validate_crate_name(Some(self.sess), &name.as_str(),
184                                             Some(i.span));
185                         name.to_string()
186                     }
187                     None => i.ident.to_string(),
188                 };
189                 Some(CrateInfo {
190                     ident: i.ident.to_string(),
191                     name: name,
192                     id: i.id,
193                     should_link: should_link(i),
194                 })
195             }
196             _ => None
197         }
198     }
199
200     // Dup of the above, but for the hir
201     fn extract_crate_info_hir(&self, i: &hir::Item) -> Option<CrateInfo> {
202         match i.node {
203             hir::ItemExternCrate(ref path_opt) => {
204                 debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
205                        i.name, path_opt);
206                 let name = match *path_opt {
207                     Some(name) => {
208                         validate_crate_name(Some(self.sess), &name.as_str(),
209                                             Some(i.span));
210                         name.to_string()
211                     }
212                     None => i.name.to_string(),
213                 };
214                 Some(CrateInfo {
215                     ident: i.name.to_string(),
216                     name: name,
217                     id: i.id,
218                     should_link: should_link_hir(i),
219                 })
220             }
221             _ => None
222         }
223     }
224
225     fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind)
226                       -> Option<ast::CrateNum> {
227         let mut ret = None;
228         self.sess.cstore.iter_crate_data(|cnum, data| {
229             if data.name != name { return }
230
231             match hash {
232                 Some(hash) if *hash == data.hash() => { ret = Some(cnum); return }
233                 Some(..) => return,
234                 None => {}
235             }
236
237             // When the hash is None we're dealing with a top-level dependency
238             // in which case we may have a specification on the command line for
239             // this library. Even though an upstream library may have loaded
240             // something of the same name, we have to make sure it was loaded
241             // from the exact same location as well.
242             //
243             // We're also sure to compare *paths*, not actual byte slices. The
244             // `source` stores paths which are normalized which may be different
245             // from the strings on the command line.
246             let source = self.sess.cstore.get_used_crate_source(cnum).unwrap();
247             if let Some(locs) = self.sess.opts.externs.get(name) {
248                 let found = locs.iter().any(|l| {
249                     let l = fs::canonicalize(l).ok();
250                     source.dylib.as_ref().map(|p| &p.0) == l.as_ref() ||
251                     source.rlib.as_ref().map(|p| &p.0) == l.as_ref()
252                 });
253                 if found {
254                     ret = Some(cnum);
255                 }
256                 return
257             }
258
259             // Alright, so we've gotten this far which means that `data` has the
260             // right name, we don't have a hash, and we don't have a --extern
261             // pointing for ourselves. We're still not quite yet done because we
262             // have to make sure that this crate was found in the crate lookup
263             // path (this is a top-level dependency) as we don't want to
264             // implicitly load anything inside the dependency lookup path.
265             let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref())
266                                   .unwrap().1;
267             if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) {
268                 ret = Some(cnum);
269             }
270         });
271         return ret;
272     }
273
274     fn verify_rustc_version(&self,
275                             name: &str,
276                             span: Span,
277                             metadata: &MetadataBlob) {
278         let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice());
279         if crate_rustc_version != Some(rustc_version()) {
280             span_err!(self.sess, span, E0514,
281                       "the crate `{}` has been compiled with {}, which is \
282                        incompatible with this version of rustc",
283                       name,
284                       crate_rustc_version
285                           .as_ref().map(|s|&**s)
286                           .unwrap_or("an old version of rustc")
287             );
288             self.sess.abort_if_errors();
289         }
290     }
291
292     fn register_crate(&mut self,
293                       root: &Option<CratePaths>,
294                       ident: &str,
295                       name: &str,
296                       span: Span,
297                       lib: loader::Library,
298                       explicitly_linked: bool)
299                       -> (ast::CrateNum, Rc<cstore::crate_metadata>,
300                           cstore::CrateSource) {
301         self.verify_rustc_version(name, span, &lib.metadata);
302
303         // Claim this crate number and cache it
304         let cnum = self.next_crate_num;
305         self.next_crate_num += 1;
306
307         // Stash paths for top-most crate locally if necessary.
308         let crate_paths = if root.is_none() {
309             Some(CratePaths {
310                 ident: ident.to_string(),
311                 dylib: lib.dylib.clone().map(|p| p.0),
312                 rlib:  lib.rlib.clone().map(|p| p.0),
313             })
314         } else {
315             None
316         };
317         // Maintain a reference to the top most crate.
318         let root = if root.is_some() { root } else { &crate_paths };
319
320         let loader::Library { dylib, rlib, metadata } = lib;
321
322         let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), span);
323         let staged_api = self.is_staged_api(metadata.as_slice());
324
325         let cmeta = Rc::new(cstore::crate_metadata {
326             name: name.to_string(),
327             local_path: RefCell::new(SmallVector::zero()),
328             index: decoder::load_index(metadata.as_slice()),
329             data: metadata,
330             cnum_map: RefCell::new(cnum_map),
331             cnum: cnum,
332             codemap_import_info: RefCell::new(vec![]),
333             span: span,
334             staged_api: staged_api,
335             explicitly_linked: Cell::new(explicitly_linked),
336         });
337
338         let source = cstore::CrateSource {
339             dylib: dylib,
340             rlib: rlib,
341             cnum: cnum,
342         };
343
344         self.sess.cstore.set_crate_data(cnum, cmeta.clone());
345         self.sess.cstore.add_used_crate_source(source.clone());
346         (cnum, cmeta, source)
347     }
348
349     fn is_staged_api(&self, data: &[u8]) -> bool {
350         let attrs = decoder::get_crate_attributes(data);
351         for attr in &attrs {
352             if &attr.name()[..] == "staged_api" {
353                 match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) }
354             }
355         }
356
357         return false;
358     }
359
360     fn resolve_crate(&mut self,
361                      root: &Option<CratePaths>,
362                      ident: &str,
363                      name: &str,
364                      hash: Option<&Svh>,
365                      span: Span,
366                      kind: PathKind,
367                      explicitly_linked: bool)
368                          -> (ast::CrateNum, Rc<cstore::crate_metadata>,
369                              cstore::CrateSource) {
370         match self.existing_match(name, hash, kind) {
371             None => {
372                 let mut load_ctxt = loader::Context {
373                     sess: self.sess,
374                     span: span,
375                     ident: ident,
376                     crate_name: name,
377                     hash: hash.map(|a| &*a),
378                     filesearch: self.sess.target_filesearch(kind),
379                     target: &self.sess.target.target,
380                     triple: &self.sess.opts.target_triple,
381                     root: root,
382                     rejected_via_hash: vec!(),
383                     rejected_via_triple: vec!(),
384                     rejected_via_kind: vec!(),
385                     should_match_name: true,
386                 };
387                 let library = load_ctxt.load_library_crate();
388                 self.register_crate(root, ident, name, span, library,
389                                     explicitly_linked)
390             }
391             Some(cnum) => {
392                 let data = self.sess.cstore.get_crate_data(cnum);
393                 if explicitly_linked && !data.explicitly_linked.get() {
394                     data.explicitly_linked.set(explicitly_linked);
395                 }
396                 (cnum, data, self.sess.cstore.get_used_crate_source(cnum).unwrap())
397             }
398         }
399     }
400
401     // Go through the crate metadata and load any crates that it references
402     fn resolve_crate_deps(&mut self,
403                           root: &Option<CratePaths>,
404                           cdata: &[u8], span : Span)
405                        -> cstore::cnum_map {
406         debug!("resolving deps of external crate");
407         // The map from crate numbers in the crate we're resolving to local crate
408         // numbers
409         decoder::get_crate_deps(cdata).iter().map(|dep| {
410             debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
411             let (local_cnum, _, _) = self.resolve_crate(root,
412                                                    &dep.name,
413                                                    &dep.name,
414                                                    Some(&dep.hash),
415                                                    span,
416                                                    PathKind::Dependency,
417                                                    dep.explicitly_linked);
418             (dep.cnum, local_cnum)
419         }).collect()
420     }
421
422     fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate {
423         let target_triple = &self.sess.opts.target_triple[..];
424         let is_cross = target_triple != config::host_triple();
425         let mut should_link = info.should_link && !is_cross;
426         let mut target_only = false;
427         let ident = info.ident.clone();
428         let name = info.name.clone();
429         let mut load_ctxt = loader::Context {
430             sess: self.sess,
431             span: span,
432             ident: &ident[..],
433             crate_name: &name[..],
434             hash: None,
435             filesearch: self.sess.host_filesearch(PathKind::Crate),
436             target: &self.sess.host,
437             triple: config::host_triple(),
438             root: &None,
439             rejected_via_hash: vec!(),
440             rejected_via_triple: vec!(),
441             rejected_via_kind: vec!(),
442             should_match_name: true,
443         };
444         let library = match load_ctxt.maybe_load_library_crate() {
445             Some(l) => l,
446             None if is_cross => {
447                 // Try loading from target crates. This will abort later if we
448                 // try to load a plugin registrar function,
449                 target_only = true;
450                 should_link = info.should_link;
451
452                 load_ctxt.target = &self.sess.target.target;
453                 load_ctxt.triple = target_triple;
454                 load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate);
455                 load_ctxt.load_library_crate()
456             }
457             None => { load_ctxt.report_load_errs(); unreachable!() },
458         };
459
460         let dylib = library.dylib.clone();
461         let register = should_link && self.existing_match(&info.name,
462                                                           None,
463                                                           PathKind::Crate).is_none();
464         let metadata = if register {
465             // Register crate now to avoid double-reading metadata
466             let (_, cmd, _) = self.register_crate(&None, &info.ident,
467                                                   &info.name, span, library,
468                                                   true);
469             PMDSource::Registered(cmd)
470         } else {
471             // Not registering the crate; just hold on to the metadata
472             PMDSource::Owned(library.metadata)
473         };
474
475         ExtensionCrate {
476             metadata: metadata,
477             dylib: dylib.map(|p| p.0),
478             target_only: target_only,
479         }
480     }
481
482     /// Read exported macros.
483     pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec<ast::MacroDef> {
484         let ci = self.extract_crate_info(item).unwrap();
485         let ekrate = self.read_extension_crate(item.span, &ci);
486
487         let source_name = format!("<{} macros>", item.ident);
488         let mut macros = vec![];
489         decoder::each_exported_macro(ekrate.metadata.as_slice(),
490                                      &*self.sess.cstore.intr,
491             |name, attrs, body| {
492                 // NB: Don't use parse::parse_tts_from_source_str because it parses with
493                 // quote_depth > 0.
494                 let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess,
495                                                               self.sess.opts.cfg.clone(),
496                                                               source_name.clone(),
497                                                               body);
498                 let lo = p.span.lo;
499                 let body = match p.parse_all_token_trees() {
500                     Ok(body) => body,
501                     Err(err) => panic!(err),
502                 };
503                 let span = mk_sp(lo, p.last_span.hi);
504                 p.abort_if_errors();
505
506                 // Mark the attrs as used
507                 for attr in &attrs {
508                     attr::mark_used(attr);
509                 }
510
511                 macros.push(ast::MacroDef {
512                     ident: ast::Ident::with_empty_ctxt(name),
513                     attrs: attrs,
514                     id: ast::DUMMY_NODE_ID,
515                     span: span,
516                     imported_from: Some(item.ident),
517                     // overridden in plugin/load.rs
518                     export: false,
519                     use_locally: false,
520                     allow_internal_unstable: false,
521
522                     body: body,
523                 });
524                 true
525             }
526         );
527         macros
528     }
529
530     /// Look for a plugin registrar. Returns library path and symbol name.
531     pub fn find_plugin_registrar(&mut self, span: Span, name: &str)
532                                  -> Option<(PathBuf, String)> {
533         let ekrate = self.read_extension_crate(span, &CrateInfo {
534              name: name.to_string(),
535              ident: name.to_string(),
536              id: ast::DUMMY_NODE_ID,
537              should_link: false,
538         });
539
540         if ekrate.target_only {
541             // Need to abort before syntax expansion.
542             let message = format!("plugin `{}` is not available for triple `{}` \
543                                    (only found {})",
544                                   name,
545                                   config::host_triple(),
546                                   self.sess.opts.target_triple);
547             span_err!(self.sess, span, E0456, "{}", &message[..]);
548             self.sess.abort_if_errors();
549         }
550
551         let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
552             .map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id));
553
554         match (ekrate.dylib.as_ref(), registrar) {
555             (Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)),
556             (None, Some(_)) => {
557                 span_err!(self.sess, span, E0457,
558                           "plugin `{}` only found in rlib format, but must be available \
559                            in dylib format",
560                           name);
561                 // No need to abort because the loading code will just ignore this
562                 // empty dylib.
563                 None
564             }
565             _ => None,
566         }
567     }
568
569     fn register_statically_included_foreign_items(&mut self) {
570         let libs = self.sess.cstore.get_used_libraries();
571         for (lib, list) in self.foreign_item_map.iter() {
572             let is_static = libs.borrow().iter().any(|&(ref name, kind)| {
573                 lib == name && kind == cstore::NativeStatic
574             });
575             if is_static {
576                 for id in list {
577                     self.sess.cstore.add_statically_included_foreign_item(*id);
578                 }
579             }
580         }
581     }
582
583     fn inject_allocator_crate(&mut self) {
584         // Make sure that we actually need an allocator, if none of our
585         // dependencies need one then we definitely don't!
586         //
587         // Also, if one of our dependencies has an explicit allocator, then we
588         // also bail out as we don't need to implicitly inject one.
589         let mut needs_allocator = false;
590         let mut found_required_allocator = false;
591         self.sess.cstore.iter_crate_data(|cnum, data| {
592             needs_allocator = needs_allocator || data.needs_allocator();
593             if data.is_allocator() {
594                 debug!("{} required by rlib and is an allocator", data.name());
595                 self.inject_allocator_dependency(cnum);
596                 found_required_allocator = found_required_allocator ||
597                     data.explicitly_linked.get();
598             }
599         });
600         if !needs_allocator || found_required_allocator { return }
601
602         // At this point we've determined that we need an allocator and no
603         // previous allocator has been activated. We look through our outputs of
604         // crate types to see what kind of allocator types we may need.
605         //
606         // The main special output type here is that rlibs do **not** need an
607         // allocator linked in (they're just object files), only final products
608         // (exes, dylibs, staticlibs) need allocators.
609         let mut need_lib_alloc = false;
610         let mut need_exe_alloc = false;
611         for ct in self.sess.crate_types.borrow().iter() {
612             match *ct {
613                 config::CrateTypeExecutable => need_exe_alloc = true,
614                 config::CrateTypeDylib |
615                 config::CrateTypeStaticlib => need_lib_alloc = true,
616                 config::CrateTypeRlib => {}
617             }
618         }
619         if !need_lib_alloc && !need_exe_alloc { return }
620
621         // The default allocator crate comes from the custom target spec, and we
622         // choose between the standard library allocator or exe allocator. This
623         // distinction exists because the default allocator for binaries (where
624         // the world is Rust) is different than library (where the world is
625         // likely *not* Rust).
626         //
627         // If a library is being produced, but we're also flagged with `-C
628         // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
629         // is being produced so we use the exe allocator instead.
630         //
631         // What this boils down to is:
632         //
633         // * Binaries use jemalloc
634         // * Staticlibs and Rust dylibs use system malloc
635         // * Rust dylibs used as dependencies to rust use jemalloc
636         let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
637             &self.sess.target.target.options.lib_allocation_crate
638         } else {
639             &self.sess.target.target.options.exe_allocation_crate
640         };
641         let (cnum, data, _) = self.resolve_crate(&None, name, name, None,
642                                                  codemap::DUMMY_SP,
643                                                  PathKind::Crate, false);
644
645         // To ensure that the `-Z allocation-crate=foo` option isn't abused, and
646         // to ensure that the allocator is indeed an allocator, we verify that
647         // the crate loaded here is indeed tagged #![allocator].
648         if !data.is_allocator() {
649             self.sess.err(&format!("the allocator crate `{}` is not tagged \
650                                     with #![allocator]", data.name()));
651         }
652
653         self.sess.injected_allocator.set(Some(cnum));
654         self.inject_allocator_dependency(cnum);
655     }
656
657     fn inject_allocator_dependency(&self, allocator: ast::CrateNum) {
658         // Before we inject any dependencies, make sure we don't inject a
659         // circular dependency by validating that this allocator crate doesn't
660         // transitively depend on any `#![needs_allocator]` crates.
661         validate(self, allocator, allocator);
662
663         // All crates tagged with `needs_allocator` do not explicitly depend on
664         // the allocator selected for this compile, but in order for this
665         // compilation to be successfully linked we need to inject a dependency
666         // (to order the crates on the command line correctly).
667         //
668         // Here we inject a dependency from all crates with #![needs_allocator]
669         // to the crate tagged with #![allocator] for this compilation unit.
670         self.sess.cstore.iter_crate_data(|cnum, data| {
671             if !data.needs_allocator() {
672                 return
673             }
674
675             info!("injecting a dep from {} to {}", cnum, allocator);
676             let mut cnum_map = data.cnum_map.borrow_mut();
677             let remote_cnum = cnum_map.len() + 1;
678             let prev = cnum_map.insert(remote_cnum as ast::CrateNum, allocator);
679             assert!(prev.is_none());
680         });
681
682         fn validate(me: &CrateReader, krate: ast::CrateNum,
683                     allocator: ast::CrateNum) {
684             let data = me.sess.cstore.get_crate_data(krate);
685             if data.needs_allocator() {
686                 let krate_name = data.name();
687                 let data = me.sess.cstore.get_crate_data(allocator);
688                 let alloc_name = data.name();
689                 me.sess.err(&format!("the allocator crate `{}` cannot depend \
690                                       on a crate that needs an allocator, but \
691                                       it depends on `{}`", alloc_name,
692                                       krate_name));
693             }
694
695             for (_, &dep) in data.cnum_map.borrow().iter() {
696                 validate(me, dep, allocator);
697             }
698         }
699     }
700 }
701
702 impl<'a, 'b> LocalCrateReader<'a, 'b> {
703     pub fn new(sess: &'a Session, map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
704         LocalCrateReader {
705             sess: sess,
706             creader: CrateReader::new(sess),
707             ast_map: map,
708         }
709     }
710
711     // Traverses an AST, reading all the information about use'd crates and
712     // extern libraries necessary for later resolving, typechecking, linking,
713     // etc.
714     pub fn read_crates(&mut self, krate: &hir::Crate) {
715         self.process_crate(krate);
716         visit::walk_crate(self, krate);
717         self.creader.inject_allocator_crate();
718
719         if log_enabled!(log::INFO) {
720             dump_crates(&self.sess.cstore);
721         }
722
723         for &(ref name, kind) in &self.sess.opts.libs {
724             register_native_lib(self.sess, None, name.clone(), kind);
725         }
726         self.creader.register_statically_included_foreign_items();
727     }
728
729     fn process_crate(&self, c: &hir::Crate) {
730         for a in c.attrs.iter().filter(|m| m.name() == "link_args") {
731             match a.value_str() {
732                 Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg),
733                 None => { /* fallthrough */ }
734             }
735         }
736     }
737
738     fn process_item(&mut self, i: &hir::Item) {
739         match i.node {
740             hir::ItemExternCrate(_) => {
741                 if !should_link_hir(i) {
742                     return;
743                 }
744
745                 match self.creader.extract_crate_info_hir(i) {
746                     Some(info) => {
747                         let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
748                                                               &info.ident,
749                                                               &info.name,
750                                                               None,
751                                                               i.span,
752                                                               PathKind::Crate,
753                                                               true);
754                         self.ast_map.with_path(i.id, |path| {
755                             cmeta.update_local_path(path)
756                         });
757                         self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
758                     }
759                     None => ()
760                 }
761             }
762             hir::ItemForeignMod(ref fm) => self.process_foreign_mod(i, fm),
763             _ => { }
764         }
765     }
766
767     fn process_foreign_mod(&mut self, i: &hir::Item, fm: &hir::ForeignMod) {
768         if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic || fm.abi == abi::PlatformIntrinsic {
769             return;
770         }
771
772         // First, add all of the custom #[link_args] attributes
773         for m in i.attrs.iter().filter(|a| a.check_name("link_args")) {
774             if let Some(linkarg) = m.value_str() {
775                 self.sess.cstore.add_used_link_args(&linkarg);
776             }
777         }
778
779         // Next, process all of the #[link(..)]-style arguments
780         for m in i.attrs.iter().filter(|a| a.check_name("link")) {
781             let items = match m.meta_item_list() {
782                 Some(item) => item,
783                 None => continue,
784             };
785             let kind = items.iter().find(|k| {
786                 k.check_name("kind")
787             }).and_then(|a| a.value_str());
788             let kind = match kind.as_ref().map(|s| &s[..]) {
789                 Some("static") => cstore::NativeStatic,
790                 Some("dylib") => cstore::NativeUnknown,
791                 Some("framework") => cstore::NativeFramework,
792                 Some(k) => {
793                     span_err!(self.sess, m.span, E0458,
794                               "unknown kind: `{}`", k);
795                     cstore::NativeUnknown
796                 }
797                 None => cstore::NativeUnknown
798             };
799             let n = items.iter().find(|n| {
800                 n.check_name("name")
801             }).and_then(|a| a.value_str());
802             let n = match n {
803                 Some(n) => n,
804                 None => {
805                     span_err!(self.sess, m.span, E0459,
806                               "#[link(...)] specified without `name = \"foo\"`");
807                     InternedString::new("foo")
808                 }
809             };
810             register_native_lib(self.sess, Some(m.span), n.to_string(), kind);
811         }
812
813         // Finally, process the #[linked_from = "..."] attribute
814         for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) {
815             let lib_name = match m.value_str() {
816                 Some(name) => name,
817                 None => continue,
818             };
819             let list = self.creader.foreign_item_map.entry(lib_name.to_string())
820                                                     .or_insert(Vec::new());
821             list.extend(fm.items.iter().map(|it| it.id));
822         }
823     }
824 }
825
826 /// Imports the codemap from an external crate into the codemap of the crate
827 /// currently being compiled (the "local crate").
828 ///
829 /// The import algorithm works analogous to how AST items are inlined from an
830 /// external crate's metadata:
831 /// For every FileMap in the external codemap an 'inline' copy is created in the
832 /// local codemap. The correspondence relation between external and local
833 /// FileMaps is recorded in the `ImportedFileMap` objects returned from this
834 /// function. When an item from an external crate is later inlined into this
835 /// crate, this correspondence information is used to translate the span
836 /// information of the inlined item so that it refers the correct positions in
837 /// the local codemap (see `astencode::DecodeContext::tr_span()`).
838 ///
839 /// The import algorithm in the function below will reuse FileMaps already
840 /// existing in the local codemap. For example, even if the FileMap of some
841 /// source file of libstd gets imported many times, there will only ever be
842 /// one FileMap object for the corresponding file in the local codemap.
843 ///
844 /// Note that imported FileMaps do not actually contain the source code of the
845 /// file they represent, just information about length, line breaks, and
846 /// multibyte characters. This information is enough to generate valid debuginfo
847 /// for items inlined from other crates.
848 pub fn import_codemap(local_codemap: &codemap::CodeMap,
849                       metadata: &MetadataBlob)
850                       -> Vec<cstore::ImportedFileMap> {
851     let external_codemap = decoder::get_imported_filemaps(metadata.as_slice());
852
853     let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| {
854         // Try to find an existing FileMap that can be reused for the filemap to
855         // be imported. A FileMap is reusable if it is exactly the same, just
856         // positioned at a different offset within the codemap.
857         let reusable_filemap = {
858             local_codemap.files
859                          .borrow()
860                          .iter()
861                          .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import))
862                          .map(|rc| rc.clone())
863         };
864
865         match reusable_filemap {
866             Some(fm) => {
867                 cstore::ImportedFileMap {
868                     original_start_pos: filemap_to_import.start_pos,
869                     original_end_pos: filemap_to_import.end_pos,
870                     translated_filemap: fm
871                 }
872             }
873             None => {
874                 // We can't reuse an existing FileMap, so allocate a new one
875                 // containing the information we need.
876                 let codemap::FileMap {
877                     name,
878                     start_pos,
879                     end_pos,
880                     lines,
881                     multibyte_chars,
882                     ..
883                 } = filemap_to_import;
884
885                 let source_length = (end_pos - start_pos).to_usize();
886
887                 // Translate line-start positions and multibyte character
888                 // position into frame of reference local to file.
889                 // `CodeMap::new_imported_filemap()` will then translate those
890                 // coordinates to their new global frame of reference when the
891                 // offset of the FileMap is known.
892                 let mut lines = lines.into_inner();
893                 for pos in &mut lines {
894                     *pos = *pos - start_pos;
895                 }
896                 let mut multibyte_chars = multibyte_chars.into_inner();
897                 for mbc in &mut multibyte_chars {
898                     mbc.pos = mbc.pos - start_pos;
899                 }
900
901                 let local_version = local_codemap.new_imported_filemap(name,
902                                                                        source_length,
903                                                                        lines,
904                                                                        multibyte_chars);
905                 cstore::ImportedFileMap {
906                     original_start_pos: start_pos,
907                     original_end_pos: end_pos,
908                     translated_filemap: local_version
909                 }
910             }
911         }
912     }).collect();
913
914     return imported_filemaps;
915
916     fn are_equal_modulo_startpos(fm1: &codemap::FileMap,
917                                  fm2: &codemap::FileMap)
918                                  -> bool {
919         if fm1.name != fm2.name {
920             return false;
921         }
922
923         let lines1 = fm1.lines.borrow();
924         let lines2 = fm2.lines.borrow();
925
926         if lines1.len() != lines2.len() {
927             return false;
928         }
929
930         for (&line1, &line2) in lines1.iter().zip(lines2.iter()) {
931             if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) {
932                 return false;
933             }
934         }
935
936         let multibytes1 = fm1.multibyte_chars.borrow();
937         let multibytes2 = fm2.multibyte_chars.borrow();
938
939         if multibytes1.len() != multibytes2.len() {
940             return false;
941         }
942
943         for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) {
944             if (mb1.bytes != mb2.bytes) ||
945                ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) {
946                 return false;
947             }
948         }
949
950         true
951     }
952 }