]>
Commit | Line | Data |
---|---|---|
85aaf69f | 1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc | 11 | //! Validates all used crates and extern libraries and loads their metadata |
223e47cc | 12 | |
92a42be0 | 13 | use cstore::{self, CStore, CrateSource, MetadataBlob}; |
92a42be0 | 14 | use loader::{self, CratePaths}; |
9e0c209e SL |
15 | use macro_import; |
16 | use schema::CrateRoot; | |
92a42be0 | 17 | |
9e0c209e | 18 | use rustc::hir::def_id::{CrateNum, DefIndex}; |
54a0048b | 19 | use rustc::hir::svh::Svh; |
9e0c209e | 20 | use rustc::middle::cstore::LoadedMacro; |
92a42be0 | 21 | use rustc::session::{config, Session}; |
a7813a04 | 22 | use rustc::session::config::PanicStrategy; |
92a42be0 | 23 | use rustc::session::search_paths::PathKind; |
9e0c209e | 24 | use rustc::middle; |
54a0048b | 25 | use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate}; |
3157f602 | 26 | use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; |
54a0048b | 27 | use rustc::hir::map as hir_map; |
223e47cc | 28 | |
e9174d1e | 29 | use std::cell::{RefCell, Cell}; |
9e0c209e | 30 | use std::ops::Deref; |
d9579d0f | 31 | use std::path::PathBuf; |
1a4d82fc | 32 | use std::rc::Rc; |
d9579d0f AL |
33 | use std::fs; |
34 | ||
1a4d82fc | 35 | use syntax::ast; |
7453a54e | 36 | use syntax::abi::Abi; |
1a4d82fc | 37 | use syntax::parse; |
e9174d1e | 38 | use syntax::attr; |
1a4d82fc | 39 | use syntax::parse::token::InternedString; |
9e0c209e | 40 | use syntax_pos::{self, Span, mk_sp}; |
1a4d82fc | 41 | use log; |
223e47cc | 42 | |
9e0c209e SL |
43 | pub struct CrateLoader<'a> { |
44 | pub sess: &'a Session, | |
45 | pub creader: CrateReader<'a>, | |
92a42be0 | 46 | cstore: &'a CStore, |
e9174d1e SL |
47 | } |
48 | ||
1a4d82fc JJ |
49 | pub struct CrateReader<'a> { |
50 | sess: &'a Session, | |
92a42be0 | 51 | cstore: &'a CStore, |
9e0c209e | 52 | next_crate_num: CrateNum, |
e9174d1e | 53 | foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>, |
54a0048b | 54 | local_crate_name: String, |
5bcae85e | 55 | local_crate_config: ast::CrateConfig, |
223e47cc LB |
56 | } |
57 | ||
1a4d82fc | 58 | fn dump_crates(cstore: &CStore) { |
e9174d1e | 59 | info!("resolved crates:"); |
1a4d82fc | 60 | cstore.iter_crate_data_origins(|_, data, opt_source| { |
e9174d1e SL |
61 | info!(" name: {}", data.name()); |
62 | info!(" cnum: {}", data.cnum); | |
63 | info!(" hash: {}", data.hash()); | |
64 | info!(" reqd: {}", data.explicitly_linked.get()); | |
1a4d82fc JJ |
65 | opt_source.map(|cs| { |
66 | let CrateSource { dylib, rlib, cnum: _ } = cs; | |
e9174d1e SL |
67 | dylib.map(|dl| info!(" dylib: {}", dl.0.display())); |
68 | rlib.map(|rl| info!(" rlib: {}", rl.0.display())); | |
1a4d82fc JJ |
69 | }); |
70 | }) | |
223e47cc LB |
71 | } |
72 | ||
85aaf69f | 73 | fn should_link(i: &ast::Item) -> bool { |
c34b1796 | 74 | !attr::contains_name(&i.attrs, "no_link") |
1a4d82fc | 75 | } |
e9174d1e | 76 | |
a7813a04 | 77 | #[derive(Debug)] |
9e0c209e | 78 | struct ExternCrateInfo { |
1a4d82fc JJ |
79 | ident: String, |
80 | name: String, | |
81 | id: ast::NodeId, | |
82 | should_link: bool, | |
83 | } | |
223e47cc | 84 | |
1a4d82fc | 85 | fn register_native_lib(sess: &Session, |
92a42be0 | 86 | cstore: &CStore, |
1a4d82fc JJ |
87 | span: Option<Span>, |
88 | name: String, | |
89 | kind: cstore::NativeLibraryKind) { | |
90 | if name.is_empty() { | |
91 | match span { | |
92 | Some(span) => { | |
9e0c209e SL |
93 | struct_span_err!(sess, span, E0454, |
94 | "#[link(name = \"\")] given with empty name") | |
95 | .span_label(span, &format!("empty name given")) | |
96 | .emit(); | |
970d7e83 | 97 | } |
1a4d82fc JJ |
98 | None => { |
99 | sess.err("empty library name given via `-l`"); | |
223e47cc LB |
100 | } |
101 | } | |
1a4d82fc | 102 | return |
223e47cc | 103 | } |
1a4d82fc JJ |
104 | let is_osx = sess.target.target.options.is_like_osx; |
105 | if kind == cstore::NativeFramework && !is_osx { | |
106 | let msg = "native frameworks are only available on OSX targets"; | |
107 | match span { | |
b039eaaf SL |
108 | Some(span) => { |
109 | span_err!(sess, span, E0455, | |
110 | "{}", msg) | |
111 | } | |
1a4d82fc JJ |
112 | None => sess.err(msg), |
113 | } | |
114 | } | |
92a42be0 | 115 | cstore.add_used_library(name, kind); |
223e47cc LB |
116 | } |
117 | ||
85aaf69f SL |
118 | // Extra info about a crate loaded for plugins or exported macros. |
119 | struct ExtensionCrate { | |
1a4d82fc | 120 | metadata: PMDSource, |
c34b1796 | 121 | dylib: Option<PathBuf>, |
1a4d82fc | 122 | target_only: bool, |
9e0c209e SL |
123 | |
124 | ident: String, | |
125 | name: String, | |
126 | span: Span, | |
127 | should_link: bool, | |
223e47cc LB |
128 | } |
129 | ||
1a4d82fc | 130 | enum PMDSource { |
3157f602 | 131 | Registered(Rc<cstore::CrateMetadata>), |
9e0c209e | 132 | Owned(loader::Library), |
1a4d82fc | 133 | } |
223e47cc | 134 | |
9e0c209e SL |
135 | impl Deref for PMDSource { |
136 | type Target = MetadataBlob; | |
137 | ||
138 | fn deref(&self) -> &MetadataBlob { | |
1a4d82fc | 139 | match *self { |
9e0c209e SL |
140 | PMDSource::Registered(ref cmd) => &cmd.blob, |
141 | PMDSource::Owned(ref lib) => &lib.metadata | |
223e47cc LB |
142 | } |
143 | } | |
144 | } | |
145 | ||
a7813a04 | 146 | enum LoadResult { |
9e0c209e | 147 | Previous(CrateNum), |
a7813a04 XL |
148 | Loaded(loader::Library), |
149 | } | |
150 | ||
9e0c209e SL |
151 | pub struct Macros { |
152 | pub macro_rules: Vec<ast::MacroDef>, | |
153 | ||
154 | /// An array of pairs where the first element is the name of the custom | |
155 | /// derive (e.g. the trait being derived) and the second element is the | |
156 | /// index of the definition. | |
157 | pub custom_derive_registrar: Option<DefIndex>, | |
158 | pub svh: Svh, | |
159 | pub dylib: Option<PathBuf>, | |
160 | } | |
161 | ||
1a4d82fc | 162 | impl<'a> CrateReader<'a> { |
54a0048b SL |
163 | pub fn new(sess: &'a Session, |
164 | cstore: &'a CStore, | |
5bcae85e SL |
165 | local_crate_name: &str, |
166 | local_crate_config: ast::CrateConfig) | |
167 | -> CrateReader<'a> { | |
1a4d82fc JJ |
168 | CrateReader { |
169 | sess: sess, | |
92a42be0 SL |
170 | cstore: cstore, |
171 | next_crate_num: cstore.next_crate_num(), | |
e9174d1e | 172 | foreign_item_map: FnvHashMap(), |
54a0048b | 173 | local_crate_name: local_crate_name.to_owned(), |
5bcae85e | 174 | local_crate_config: local_crate_config, |
223e47cc | 175 | } |
223e47cc | 176 | } |
223e47cc | 177 | |
9e0c209e | 178 | fn extract_crate_info(&self, i: &ast::Item) -> Option<ExternCrateInfo> { |
1a4d82fc | 179 | match i.node { |
7453a54e | 180 | ast::ItemKind::ExternCrate(ref path_opt) => { |
1a4d82fc | 181 | debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", |
c1a9b12d | 182 | i.ident, path_opt); |
1a4d82fc | 183 | let name = match *path_opt { |
c34b1796 | 184 | Some(name) => { |
c1a9b12d | 185 | validate_crate_name(Some(self.sess), &name.as_str(), |
1a4d82fc | 186 | Some(i.span)); |
c1a9b12d | 187 | name.to_string() |
1a4d82fc | 188 | } |
c1a9b12d | 189 | None => i.ident.to_string(), |
1a4d82fc | 190 | }; |
9e0c209e | 191 | Some(ExternCrateInfo { |
c1a9b12d | 192 | ident: i.ident.to_string(), |
1a4d82fc | 193 | name: name, |
85aaf69f | 194 | id: i.id, |
1a4d82fc JJ |
195 | should_link: should_link(i), |
196 | }) | |
197 | } | |
198 | _ => None | |
199 | } | |
200 | } | |
223e47cc | 201 | |
85aaf69f | 202 | fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) |
9e0c209e | 203 | -> Option<CrateNum> { |
1a4d82fc | 204 | let mut ret = None; |
92a42be0 | 205 | self.cstore.iter_crate_data(|cnum, data| { |
1a4d82fc | 206 | if data.name != name { return } |
223e47cc | 207 | |
1a4d82fc JJ |
208 | match hash { |
209 | Some(hash) if *hash == data.hash() => { ret = Some(cnum); return } | |
210 | Some(..) => return, | |
211 | None => {} | |
212 | } | |
223e47cc | 213 | |
85aaf69f SL |
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. | |
1a4d82fc JJ |
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. | |
92a42be0 | 223 | let source = self.cstore.used_crate_source(cnum); |
85aaf69f SL |
224 | if let Some(locs) = self.sess.opts.externs.get(name) { |
225 | let found = locs.iter().any(|l| { | |
d9579d0f | 226 | let l = fs::canonicalize(l).ok(); |
85aaf69f SL |
227 | source.dylib.as_ref().map(|p| &p.0) == l.as_ref() || |
228 | source.rlib.as_ref().map(|p| &p.0) == l.as_ref() | |
229 | }); | |
230 | if found { | |
231 | ret = Some(cnum); | |
1a4d82fc | 232 | } |
85aaf69f SL |
233 | return |
234 | } | |
235 | ||
236 | // Alright, so we've gotten this far which means that `data` has the | |
237 | // right name, we don't have a hash, and we don't have a --extern | |
238 | // pointing for ourselves. We're still not quite yet done because we | |
239 | // have to make sure that this crate was found in the crate lookup | |
240 | // path (this is a top-level dependency) as we don't want to | |
241 | // implicitly load anything inside the dependency lookup path. | |
242 | let prev_kind = source.dylib.as_ref().or(source.rlib.as_ref()) | |
243 | .unwrap().1; | |
244 | if ret.is_none() && (prev_kind == kind || prev_kind == PathKind::All) { | |
245 | ret = Some(cnum); | |
1a4d82fc JJ |
246 | } |
247 | }); | |
248 | return ret; | |
249 | } | |
223e47cc | 250 | |
54a0048b SL |
251 | fn verify_no_symbol_conflicts(&self, |
252 | span: Span, | |
9e0c209e | 253 | root: &CrateRoot) { |
54a0048b | 254 | // Check for (potential) conflicts with the local crate |
9e0c209e SL |
255 | if self.local_crate_name == root.name && |
256 | self.sess.local_crate_disambiguator() == &root.disambiguator[..] { | |
54a0048b SL |
257 | span_fatal!(self.sess, span, E0519, |
258 | "the current crate is indistinguishable from one of its \ | |
259 | dependencies: it has the same crate-name `{}` and was \ | |
260 | compiled with the same `-C metadata` arguments. This \ | |
261 | will result in symbol conflicts between the two.", | |
9e0c209e | 262 | root.name) |
54a0048b SL |
263 | } |
264 | ||
54a0048b SL |
265 | // Check for conflicts with any crate loaded so far |
266 | self.cstore.iter_crate_data(|_, other| { | |
9e0c209e SL |
267 | if other.name() == root.name && // same crate-name |
268 | other.disambiguator() == root.disambiguator && // same crate-disambiguator | |
269 | other.hash() != root.hash { // but different SVH | |
54a0048b SL |
270 | span_fatal!(self.sess, span, E0523, |
271 | "found two different crates with name `{}` that are \ | |
272 | not distinguished by differing `-C metadata`. This \ | |
273 | will result in symbol conflicts between the two.", | |
9e0c209e | 274 | root.name) |
54a0048b SL |
275 | } |
276 | }); | |
277 | } | |
278 | ||
1a4d82fc JJ |
279 | fn register_crate(&mut self, |
280 | root: &Option<CratePaths>, | |
281 | ident: &str, | |
282 | name: &str, | |
283 | span: Span, | |
e9174d1e SL |
284 | lib: loader::Library, |
285 | explicitly_linked: bool) | |
9e0c209e | 286 | -> (CrateNum, Rc<cstore::CrateMetadata>, |
1a4d82fc | 287 | cstore::CrateSource) { |
9e0c209e SL |
288 | info!("register crate `extern crate {} as {}`", name, ident); |
289 | let crate_root = lib.metadata.get_root(); | |
290 | self.verify_no_symbol_conflicts(span, &crate_root); | |
b039eaaf | 291 | |
223e47cc | 292 | // Claim this crate number and cache it |
1a4d82fc | 293 | let cnum = self.next_crate_num; |
9e0c209e | 294 | self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1); |
1a4d82fc JJ |
295 | |
296 | // Stash paths for top-most crate locally if necessary. | |
297 | let crate_paths = if root.is_none() { | |
298 | Some(CratePaths { | |
299 | ident: ident.to_string(), | |
85aaf69f SL |
300 | dylib: lib.dylib.clone().map(|p| p.0), |
301 | rlib: lib.rlib.clone().map(|p| p.0), | |
1a4d82fc JJ |
302 | }) |
303 | } else { | |
304 | None | |
305 | }; | |
306 | // Maintain a reference to the top most crate. | |
307 | let root = if root.is_some() { root } else { &crate_paths }; | |
308 | ||
c34b1796 | 309 | let loader::Library { dylib, rlib, metadata } = lib; |
1a4d82fc | 310 | |
9e0c209e SL |
311 | let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span); |
312 | ||
313 | if crate_root.macro_derive_registrar.is_some() { | |
314 | self.sess.span_err(span, "crates of the `rustc-macro` crate type \ | |
315 | cannot be linked at runtime"); | |
316 | } | |
1a4d82fc | 317 | |
3157f602 | 318 | let cmeta = Rc::new(cstore::CrateMetadata { |
1a4d82fc | 319 | name: name.to_string(), |
54a0048b | 320 | extern_crate: Cell::new(None), |
9e0c209e SL |
321 | key_map: metadata.load_key_map(crate_root.index), |
322 | root: crate_root, | |
323 | blob: metadata, | |
e9174d1e | 324 | cnum_map: RefCell::new(cnum_map), |
223e47cc | 325 | cnum: cnum, |
62682a34 | 326 | codemap_import_info: RefCell::new(vec![]), |
e9174d1e | 327 | explicitly_linked: Cell::new(explicitly_linked), |
223e47cc | 328 | }); |
1a4d82fc JJ |
329 | |
330 | let source = cstore::CrateSource { | |
331 | dylib: dylib, | |
332 | rlib: rlib, | |
333 | cnum: cnum, | |
334 | }; | |
335 | ||
92a42be0 SL |
336 | self.cstore.set_crate_data(cnum, cmeta.clone()); |
337 | self.cstore.add_used_crate_source(source.clone()); | |
1a4d82fc JJ |
338 | (cnum, cmeta, source) |
339 | } | |
340 | ||
341 | fn resolve_crate(&mut self, | |
342 | root: &Option<CratePaths>, | |
343 | ident: &str, | |
344 | name: &str, | |
345 | hash: Option<&Svh>, | |
346 | span: Span, | |
e9174d1e SL |
347 | kind: PathKind, |
348 | explicitly_linked: bool) | |
9e0c209e SL |
349 | -> (CrateNum, Rc<cstore::CrateMetadata>, cstore::CrateSource) { |
350 | info!("resolving crate `extern crate {} as {}`", name, ident); | |
92a42be0 | 351 | let result = match self.existing_match(name, hash, kind) { |
a7813a04 | 352 | Some(cnum) => LoadResult::Previous(cnum), |
1a4d82fc | 353 | None => { |
9e0c209e | 354 | info!("falling back to a load"); |
1a4d82fc JJ |
355 | let mut load_ctxt = loader::Context { |
356 | sess: self.sess, | |
357 | span: span, | |
358 | ident: ident, | |
359 | crate_name: name, | |
360 | hash: hash.map(|a| &*a), | |
361 | filesearch: self.sess.target_filesearch(kind), | |
85aaf69f | 362 | target: &self.sess.target.target, |
c34b1796 | 363 | triple: &self.sess.opts.target_triple, |
1a4d82fc JJ |
364 | root: root, |
365 | rejected_via_hash: vec!(), | |
366 | rejected_via_triple: vec!(), | |
85aaf69f | 367 | rejected_via_kind: vec!(), |
a7813a04 | 368 | rejected_via_version: vec!(), |
1a4d82fc JJ |
369 | should_match_name: true, |
370 | }; | |
a7813a04 XL |
371 | match self.load(&mut load_ctxt) { |
372 | Some(result) => result, | |
373 | None => load_ctxt.report_load_errs(), | |
374 | } | |
e9174d1e | 375 | } |
92a42be0 SL |
376 | }; |
377 | ||
378 | match result { | |
a7813a04 | 379 | LoadResult::Previous(cnum) => { |
92a42be0 | 380 | let data = self.cstore.get_crate_data(cnum); |
e9174d1e SL |
381 | if explicitly_linked && !data.explicitly_linked.get() { |
382 | data.explicitly_linked.set(explicitly_linked); | |
383 | } | |
92a42be0 SL |
384 | (cnum, data, self.cstore.used_crate_source(cnum)) |
385 | } | |
a7813a04 | 386 | LoadResult::Loaded(library) => { |
92a42be0 SL |
387 | self.register_crate(root, ident, name, span, library, |
388 | explicitly_linked) | |
1a4d82fc | 389 | } |
1a4d82fc JJ |
390 | } |
391 | } | |
392 | ||
a7813a04 XL |
393 | fn load(&mut self, loader: &mut loader::Context) -> Option<LoadResult> { |
394 | let library = match loader.maybe_load_library_crate() { | |
395 | Some(lib) => lib, | |
396 | None => return None, | |
397 | }; | |
398 | ||
399 | // In the case that we're loading a crate, but not matching | |
400 | // against a hash, we could load a crate which has the same hash | |
401 | // as an already loaded crate. If this is the case prevent | |
402 | // duplicates by just using the first crate. | |
403 | // | |
404 | // Note that we only do this for target triple crates, though, as we | |
405 | // don't want to match a host crate against an equivalent target one | |
406 | // already loaded. | |
9e0c209e | 407 | let root = library.metadata.get_root(); |
a7813a04 | 408 | if loader.triple == self.sess.opts.target_triple { |
a7813a04 XL |
409 | let mut result = LoadResult::Loaded(library); |
410 | self.cstore.iter_crate_data(|cnum, data| { | |
9e0c209e | 411 | if data.name() == root.name && root.hash == data.hash() { |
a7813a04 | 412 | assert!(loader.hash.is_none()); |
9e0c209e | 413 | info!("load success, going to previous cnum: {}", cnum); |
a7813a04 XL |
414 | result = LoadResult::Previous(cnum); |
415 | } | |
416 | }); | |
417 | Some(result) | |
418 | } else { | |
419 | Some(LoadResult::Loaded(library)) | |
420 | } | |
421 | } | |
422 | ||
54a0048b | 423 | fn update_extern_crate(&mut self, |
9e0c209e | 424 | cnum: CrateNum, |
3157f602 | 425 | mut extern_crate: ExternCrate, |
9e0c209e | 426 | visited: &mut FnvHashSet<(CrateNum, bool)>) |
54a0048b | 427 | { |
3157f602 XL |
428 | if !visited.insert((cnum, extern_crate.direct)) { return } |
429 | ||
54a0048b SL |
430 | let cmeta = self.cstore.get_crate_data(cnum); |
431 | let old_extern_crate = cmeta.extern_crate.get(); | |
432 | ||
433 | // Prefer: | |
434 | // - something over nothing (tuple.0); | |
435 | // - direct extern crate to indirect (tuple.1); | |
436 | // - shorter paths to longer (tuple.2). | |
437 | let new_rank = (true, extern_crate.direct, !extern_crate.path_len); | |
438 | let old_rank = match old_extern_crate { | |
439 | None => (false, false, !0), | |
440 | Some(ref c) => (true, c.direct, !c.path_len), | |
441 | }; | |
442 | ||
443 | if old_rank >= new_rank { | |
444 | return; // no change needed | |
445 | } | |
446 | ||
447 | cmeta.extern_crate.set(Some(extern_crate)); | |
54a0048b SL |
448 | // Propagate the extern crate info to dependencies. |
449 | extern_crate.direct = false; | |
3157f602 XL |
450 | for &dep_cnum in cmeta.cnum_map.borrow().iter() { |
451 | self.update_extern_crate(dep_cnum, extern_crate, visited); | |
54a0048b SL |
452 | } |
453 | } | |
454 | ||
1a4d82fc JJ |
455 | // Go through the crate metadata and load any crates that it references |
456 | fn resolve_crate_deps(&mut self, | |
457 | root: &Option<CratePaths>, | |
9e0c209e SL |
458 | crate_root: &CrateRoot, |
459 | metadata: &MetadataBlob, | |
460 | krate: CrateNum, | |
3157f602 XL |
461 | span: Span) |
462 | -> cstore::CrateNumMap { | |
1a4d82fc JJ |
463 | debug!("resolving deps of external crate"); |
464 | // The map from crate numbers in the crate we're resolving to local crate | |
465 | // numbers | |
9e0c209e SL |
466 | let deps = crate_root.crate_deps.decode(metadata); |
467 | let map: FnvHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { | |
1a4d82fc | 468 | debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); |
9e0c209e SL |
469 | let (local_cnum, ..) = self.resolve_crate(root, |
470 | &dep.name.as_str(), | |
471 | &dep.name.as_str(), | |
54a0048b SL |
472 | Some(&dep.hash), |
473 | span, | |
474 | PathKind::Dependency, | |
475 | dep.explicitly_linked); | |
9e0c209e | 476 | (CrateNum::new(crate_num + 1), local_cnum) |
3157f602 XL |
477 | }).collect(); |
478 | ||
9e0c209e | 479 | let max_cnum = map.values().cloned().max().map(|cnum| cnum.as_u32()).unwrap_or(0); |
3157f602 XL |
480 | |
481 | // we map 0 and all other holes in the map to our parent crate. The "additional" | |
482 | // self-dependencies should be harmless. | |
9e0c209e SL |
483 | (0..max_cnum+1).map(|cnum| { |
484 | map.get(&CrateNum::from_u32(cnum)).cloned().unwrap_or(krate) | |
485 | }).collect() | |
1a4d82fc JJ |
486 | } |
487 | ||
9e0c209e SL |
488 | fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate { |
489 | info!("read extension crate {} `extern crate {} as {}` linked={}", | |
490 | info.id, info.name, info.ident, info.should_link); | |
c34b1796 | 491 | let target_triple = &self.sess.opts.target_triple[..]; |
1a4d82fc JJ |
492 | let is_cross = target_triple != config::host_triple(); |
493 | let mut should_link = info.should_link && !is_cross; | |
494 | let mut target_only = false; | |
495 | let ident = info.ident.clone(); | |
496 | let name = info.name.clone(); | |
497 | let mut load_ctxt = loader::Context { | |
498 | sess: self.sess, | |
499 | span: span, | |
85aaf69f SL |
500 | ident: &ident[..], |
501 | crate_name: &name[..], | |
1a4d82fc JJ |
502 | hash: None, |
503 | filesearch: self.sess.host_filesearch(PathKind::Crate), | |
85aaf69f | 504 | target: &self.sess.host, |
1a4d82fc JJ |
505 | triple: config::host_triple(), |
506 | root: &None, | |
507 | rejected_via_hash: vec!(), | |
508 | rejected_via_triple: vec!(), | |
85aaf69f | 509 | rejected_via_kind: vec!(), |
a7813a04 | 510 | rejected_via_version: vec!(), |
1a4d82fc JJ |
511 | should_match_name: true, |
512 | }; | |
a7813a04 XL |
513 | let library = self.load(&mut load_ctxt).or_else(|| { |
514 | if !is_cross { | |
515 | return None | |
1a4d82fc | 516 | } |
a7813a04 XL |
517 | // Try loading from target crates. This will abort later if we |
518 | // try to load a plugin registrar function, | |
519 | target_only = true; | |
520 | should_link = info.should_link; | |
521 | ||
522 | load_ctxt.target = &self.sess.target.target; | |
523 | load_ctxt.triple = target_triple; | |
524 | load_ctxt.filesearch = self.sess.target_filesearch(PathKind::Crate); | |
525 | ||
526 | self.load(&mut load_ctxt) | |
527 | }); | |
528 | let library = match library { | |
529 | Some(l) => l, | |
530 | None => load_ctxt.report_load_errs(), | |
223e47cc LB |
531 | }; |
532 | ||
a7813a04 XL |
533 | let (dylib, metadata) = match library { |
534 | LoadResult::Previous(cnum) => { | |
535 | let dylib = self.cstore.opt_used_crate_source(cnum).unwrap().dylib; | |
536 | let data = self.cstore.get_crate_data(cnum); | |
537 | (dylib, PMDSource::Registered(data)) | |
538 | } | |
539 | LoadResult::Loaded(library) => { | |
540 | let dylib = library.dylib.clone(); | |
9e0c209e | 541 | let metadata = PMDSource::Owned(library); |
a7813a04 XL |
542 | (dylib, metadata) |
543 | } | |
1a4d82fc JJ |
544 | }; |
545 | ||
85aaf69f | 546 | ExtensionCrate { |
1a4d82fc | 547 | metadata: metadata, |
85aaf69f | 548 | dylib: dylib.map(|p| p.0), |
1a4d82fc | 549 | target_only: target_only, |
9e0c209e SL |
550 | name: info.name.to_string(), |
551 | ident: info.ident.to_string(), | |
552 | span: span, | |
553 | should_link: should_link, | |
1a4d82fc | 554 | } |
223e47cc | 555 | } |
223e47cc | 556 | |
9e0c209e | 557 | pub fn read_macros(&mut self, item: &ast::Item) -> Macros { |
e9174d1e SL |
558 | let ci = self.extract_crate_info(item).unwrap(); |
559 | let ekrate = self.read_extension_crate(item.span, &ci); | |
1a4d82fc | 560 | |
9e0c209e | 561 | let root = ekrate.metadata.get_root(); |
e9174d1e | 562 | let source_name = format!("<{} macros>", item.ident); |
9e0c209e SL |
563 | let mut ret = Macros { |
564 | macro_rules: Vec::new(), | |
565 | custom_derive_registrar: None, | |
566 | svh: root.hash, | |
567 | dylib: None, | |
568 | }; | |
569 | for def in root.macro_defs.decode(&*ekrate.metadata) { | |
570 | // NB: Don't use parse::parse_tts_from_source_str because it parses with | |
571 | // quote_depth > 0. | |
572 | let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, | |
573 | self.local_crate_config.clone(), | |
574 | source_name.clone(), | |
575 | def.body); | |
576 | let lo = p.span.lo; | |
577 | let body = match p.parse_all_token_trees() { | |
578 | Ok(body) => body, | |
579 | Err(mut err) => { | |
580 | err.emit(); | |
581 | self.sess.abort_if_errors(); | |
582 | unreachable!(); | |
b039eaaf | 583 | } |
9e0c209e SL |
584 | }; |
585 | let local_span = mk_sp(lo, p.last_span.hi); | |
b039eaaf | 586 | |
9e0c209e SL |
587 | // Mark the attrs as used |
588 | for attr in &def.attrs { | |
589 | attr::mark_used(attr); | |
1a4d82fc | 590 | } |
9e0c209e SL |
591 | |
592 | ret.macro_rules.push(ast::MacroDef { | |
593 | ident: ast::Ident::with_empty_ctxt(def.name), | |
594 | attrs: def.attrs, | |
595 | id: ast::DUMMY_NODE_ID, | |
596 | span: local_span, | |
597 | imported_from: Some(item.ident), | |
598 | // overridden in plugin/load.rs | |
599 | export: false, | |
600 | use_locally: false, | |
601 | allow_internal_unstable: false, | |
602 | ||
603 | body: body, | |
604 | }); | |
605 | self.sess.imported_macro_spans.borrow_mut() | |
606 | .insert(local_span, (def.name.as_str().to_string(), def.span)); | |
607 | } | |
608 | ||
609 | match root.macro_derive_registrar { | |
610 | Some(id) => ret.custom_derive_registrar = Some(id), | |
611 | ||
612 | // If this crate is not a rustc-macro crate then we might be able to | |
613 | // register it with the local crate store to prevent loading the | |
614 | // metadata twice. | |
615 | // | |
616 | // If it's a rustc-macro crate, though, then we definitely don't | |
617 | // want to register it with the local crate store as we're just | |
618 | // going to use it as we would a plugin. | |
619 | None => { | |
620 | ekrate.register(self); | |
621 | return ret | |
622 | } | |
623 | } | |
624 | ||
625 | self.cstore.add_used_for_derive_macros(item); | |
626 | ret.dylib = ekrate.dylib.clone(); | |
627 | if ret.dylib.is_none() { | |
628 | span_bug!(item.span, "rustc-macro crate not dylib"); | |
629 | } | |
630 | ||
631 | if ekrate.target_only { | |
632 | let message = format!("rustc-macro crate is not available for \ | |
633 | triple `{}` (only found {})", | |
634 | config::host_triple(), | |
635 | self.sess.opts.target_triple); | |
636 | self.sess.span_fatal(item.span, &message); | |
637 | } | |
638 | ||
639 | return ret | |
1a4d82fc JJ |
640 | } |
641 | ||
3157f602 XL |
642 | /// Look for a plugin registrar. Returns library path, crate |
643 | /// SVH and DefIndex of the registrar function. | |
c34b1796 | 644 | pub fn find_plugin_registrar(&mut self, span: Span, name: &str) |
3157f602 | 645 | -> Option<(PathBuf, Svh, DefIndex)> { |
9e0c209e | 646 | let ekrate = self.read_extension_crate(span, &ExternCrateInfo { |
85aaf69f SL |
647 | name: name.to_string(), |
648 | ident: name.to_string(), | |
649 | id: ast::DUMMY_NODE_ID, | |
650 | should_link: false, | |
651 | }); | |
652 | ||
653 | if ekrate.target_only { | |
1a4d82fc | 654 | // Need to abort before syntax expansion. |
85aaf69f | 655 | let message = format!("plugin `{}` is not available for triple `{}` \ |
1a4d82fc | 656 | (only found {})", |
85aaf69f | 657 | name, |
1a4d82fc JJ |
658 | config::host_triple(), |
659 | self.sess.opts.target_triple); | |
7453a54e | 660 | span_fatal!(self.sess, span, E0456, "{}", &message[..]); |
1a4d82fc JJ |
661 | } |
662 | ||
9e0c209e SL |
663 | let root = ekrate.metadata.get_root(); |
664 | match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) { | |
3157f602 | 665 | (Some(dylib), Some(reg)) => { |
9e0c209e | 666 | Some((dylib.to_path_buf(), root.hash, reg)) |
3157f602 | 667 | } |
1a4d82fc | 668 | (None, Some(_)) => { |
b039eaaf SL |
669 | span_err!(self.sess, span, E0457, |
670 | "plugin `{}` only found in rlib format, but must be available \ | |
671 | in dylib format", | |
672 | name); | |
1a4d82fc JJ |
673 | // No need to abort because the loading code will just ignore this |
674 | // empty dylib. | |
675 | None | |
676 | } | |
677 | _ => None, | |
223e47cc LB |
678 | } |
679 | } | |
e9174d1e SL |
680 | |
681 | fn register_statically_included_foreign_items(&mut self) { | |
92a42be0 | 682 | let libs = self.cstore.get_used_libraries(); |
e9174d1e SL |
683 | for (lib, list) in self.foreign_item_map.iter() { |
684 | let is_static = libs.borrow().iter().any(|&(ref name, kind)| { | |
685 | lib == name && kind == cstore::NativeStatic | |
686 | }); | |
687 | if is_static { | |
688 | for id in list { | |
92a42be0 | 689 | self.cstore.add_statically_included_foreign_item(*id); |
e9174d1e SL |
690 | } |
691 | } | |
692 | } | |
693 | } | |
694 | ||
a7813a04 XL |
695 | fn inject_panic_runtime(&mut self, krate: &ast::Crate) { |
696 | // If we're only compiling an rlib, then there's no need to select a | |
697 | // panic runtime, so we just skip this section entirely. | |
698 | let any_non_rlib = self.sess.crate_types.borrow().iter().any(|ct| { | |
699 | *ct != config::CrateTypeRlib | |
700 | }); | |
701 | if !any_non_rlib { | |
702 | info!("panic runtime injection skipped, only generating rlib"); | |
703 | return | |
704 | } | |
705 | ||
706 | // If we need a panic runtime, we try to find an existing one here. At | |
707 | // the same time we perform some general validation of the DAG we've got | |
708 | // going such as ensuring everything has a compatible panic strategy. | |
709 | // | |
710 | // The logic for finding the panic runtime here is pretty much the same | |
711 | // as the allocator case with the only addition that the panic strategy | |
712 | // compilation mode also comes into play. | |
713 | let desired_strategy = self.sess.opts.cg.panic.clone(); | |
714 | let mut runtime_found = false; | |
715 | let mut needs_panic_runtime = attr::contains_name(&krate.attrs, | |
716 | "needs_panic_runtime"); | |
717 | self.cstore.iter_crate_data(|cnum, data| { | |
718 | needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime(); | |
719 | if data.is_panic_runtime() { | |
720 | // Inject a dependency from all #![needs_panic_runtime] to this | |
721 | // #![panic_runtime] crate. | |
722 | self.inject_dependency_if(cnum, "a panic runtime", | |
723 | &|data| data.needs_panic_runtime()); | |
724 | runtime_found = runtime_found || data.explicitly_linked.get(); | |
725 | } | |
726 | }); | |
727 | ||
728 | // If an explicitly linked and matching panic runtime was found, or if | |
729 | // we just don't need one at all, then we're done here and there's | |
730 | // nothing else to do. | |
731 | if !needs_panic_runtime || runtime_found { | |
732 | return | |
733 | } | |
734 | ||
735 | // By this point we know that we (a) need a panic runtime and (b) no | |
736 | // panic runtime was explicitly linked. Here we just load an appropriate | |
737 | // default runtime for our panic strategy and then inject the | |
738 | // dependencies. | |
739 | // | |
740 | // We may resolve to an already loaded crate (as the crate may not have | |
741 | // been explicitly linked prior to this) and we may re-inject | |
742 | // dependencies again, but both of those situations are fine. | |
743 | // | |
744 | // Also note that we have yet to perform validation of the crate graph | |
745 | // in terms of everyone has a compatible panic runtime format, that's | |
746 | // performed later as part of the `dependency_format` module. | |
747 | let name = match desired_strategy { | |
748 | PanicStrategy::Unwind => "panic_unwind", | |
749 | PanicStrategy::Abort => "panic_abort", | |
750 | }; | |
751 | info!("panic runtime not found -- loading {}", name); | |
752 | ||
753 | let (cnum, data, _) = self.resolve_crate(&None, name, name, None, | |
3157f602 | 754 | syntax_pos::DUMMY_SP, |
a7813a04 XL |
755 | PathKind::Crate, false); |
756 | ||
757 | // Sanity check the loaded crate to ensure it is indeed a panic runtime | |
758 | // and the panic strategy is indeed what we thought it was. | |
759 | if !data.is_panic_runtime() { | |
760 | self.sess.err(&format!("the crate `{}` is not a panic runtime", | |
761 | name)); | |
762 | } | |
763 | if data.panic_strategy() != desired_strategy { | |
764 | self.sess.err(&format!("the crate `{}` does not have the panic \ | |
765 | strategy `{}`", | |
766 | name, desired_strategy.desc())); | |
767 | } | |
768 | ||
769 | self.sess.injected_panic_runtime.set(Some(cnum)); | |
770 | self.inject_dependency_if(cnum, "a panic runtime", | |
771 | &|data| data.needs_panic_runtime()); | |
772 | } | |
773 | ||
e9174d1e SL |
774 | fn inject_allocator_crate(&mut self) { |
775 | // Make sure that we actually need an allocator, if none of our | |
776 | // dependencies need one then we definitely don't! | |
777 | // | |
778 | // Also, if one of our dependencies has an explicit allocator, then we | |
779 | // also bail out as we don't need to implicitly inject one. | |
780 | let mut needs_allocator = false; | |
781 | let mut found_required_allocator = false; | |
92a42be0 | 782 | self.cstore.iter_crate_data(|cnum, data| { |
e9174d1e SL |
783 | needs_allocator = needs_allocator || data.needs_allocator(); |
784 | if data.is_allocator() { | |
a7813a04 XL |
785 | info!("{} required by rlib and is an allocator", data.name()); |
786 | self.inject_dependency_if(cnum, "an allocator", | |
787 | &|data| data.needs_allocator()); | |
e9174d1e SL |
788 | found_required_allocator = found_required_allocator || |
789 | data.explicitly_linked.get(); | |
790 | } | |
791 | }); | |
792 | if !needs_allocator || found_required_allocator { return } | |
793 | ||
794 | // At this point we've determined that we need an allocator and no | |
795 | // previous allocator has been activated. We look through our outputs of | |
796 | // crate types to see what kind of allocator types we may need. | |
797 | // | |
798 | // The main special output type here is that rlibs do **not** need an | |
799 | // allocator linked in (they're just object files), only final products | |
800 | // (exes, dylibs, staticlibs) need allocators. | |
801 | let mut need_lib_alloc = false; | |
802 | let mut need_exe_alloc = false; | |
803 | for ct in self.sess.crate_types.borrow().iter() { | |
804 | match *ct { | |
805 | config::CrateTypeExecutable => need_exe_alloc = true, | |
806 | config::CrateTypeDylib | | |
9e0c209e | 807 | config::CrateTypeRustcMacro | |
a7813a04 | 808 | config::CrateTypeCdylib | |
e9174d1e SL |
809 | config::CrateTypeStaticlib => need_lib_alloc = true, |
810 | config::CrateTypeRlib => {} | |
811 | } | |
812 | } | |
813 | if !need_lib_alloc && !need_exe_alloc { return } | |
814 | ||
815 | // The default allocator crate comes from the custom target spec, and we | |
816 | // choose between the standard library allocator or exe allocator. This | |
817 | // distinction exists because the default allocator for binaries (where | |
818 | // the world is Rust) is different than library (where the world is | |
819 | // likely *not* Rust). | |
820 | // | |
821 | // If a library is being produced, but we're also flagged with `-C | |
822 | // prefer-dynamic`, then we interpret this as a *Rust* dynamic library | |
823 | // is being produced so we use the exe allocator instead. | |
824 | // | |
825 | // What this boils down to is: | |
826 | // | |
827 | // * Binaries use jemalloc | |
828 | // * Staticlibs and Rust dylibs use system malloc | |
829 | // * Rust dylibs used as dependencies to rust use jemalloc | |
830 | let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic { | |
831 | &self.sess.target.target.options.lib_allocation_crate | |
832 | } else { | |
833 | &self.sess.target.target.options.exe_allocation_crate | |
834 | }; | |
835 | let (cnum, data, _) = self.resolve_crate(&None, name, name, None, | |
3157f602 | 836 | syntax_pos::DUMMY_SP, |
e9174d1e SL |
837 | PathKind::Crate, false); |
838 | ||
a7813a04 XL |
839 | // Sanity check the crate we loaded to ensure that it is indeed an |
840 | // allocator. | |
e9174d1e SL |
841 | if !data.is_allocator() { |
842 | self.sess.err(&format!("the allocator crate `{}` is not tagged \ | |
843 | with #![allocator]", data.name())); | |
844 | } | |
845 | ||
846 | self.sess.injected_allocator.set(Some(cnum)); | |
a7813a04 XL |
847 | self.inject_dependency_if(cnum, "an allocator", |
848 | &|data| data.needs_allocator()); | |
e9174d1e SL |
849 | } |
850 | ||
a7813a04 | 851 | fn inject_dependency_if(&self, |
9e0c209e | 852 | krate: CrateNum, |
a7813a04 | 853 | what: &str, |
3157f602 | 854 | needs_dep: &Fn(&cstore::CrateMetadata) -> bool) { |
a7813a04 XL |
855 | // don't perform this validation if the session has errors, as one of |
856 | // those errors may indicate a circular dependency which could cause | |
857 | // this to stack overflow. | |
858 | if self.sess.has_errors() { | |
859 | return | |
860 | } | |
861 | ||
e9174d1e | 862 | // Before we inject any dependencies, make sure we don't inject a |
a7813a04 XL |
863 | // circular dependency by validating that this crate doesn't |
864 | // transitively depend on any crates satisfying `needs_dep`. | |
3157f602 XL |
865 | for dep in self.cstore.crate_dependencies_in_rpo(krate) { |
866 | let data = self.cstore.get_crate_data(dep); | |
867 | if needs_dep(&data) { | |
868 | self.sess.err(&format!("the crate `{}` cannot depend \ | |
869 | on a crate that needs {}, but \ | |
870 | it depends on `{}`", | |
871 | self.cstore.get_crate_data(krate).name(), | |
872 | what, | |
873 | data.name())); | |
874 | } | |
875 | } | |
a7813a04 XL |
876 | |
877 | // All crates satisfying `needs_dep` do not explicitly depend on the | |
878 | // crate provided for this compile, but in order for this compilation to | |
879 | // be successfully linked we need to inject a dependency (to order the | |
880 | // crates on the command line correctly). | |
92a42be0 | 881 | self.cstore.iter_crate_data(|cnum, data| { |
a7813a04 | 882 | if !needs_dep(data) { |
e9174d1e SL |
883 | return |
884 | } | |
885 | ||
a7813a04 | 886 | info!("injecting a dep from {} to {}", cnum, krate); |
3157f602 | 887 | data.cnum_map.borrow_mut().push(krate); |
e9174d1e | 888 | }); |
e9174d1e SL |
889 | } |
890 | } | |
891 | ||
9e0c209e SL |
892 | impl ExtensionCrate { |
893 | fn register(self, creader: &mut CrateReader) { | |
894 | if !self.should_link { | |
895 | return | |
e9174d1e SL |
896 | } |
897 | ||
9e0c209e SL |
898 | let library = match self.metadata { |
899 | PMDSource::Owned(lib) => lib, | |
900 | PMDSource::Registered(_) => return, | |
901 | }; | |
e9174d1e | 902 | |
9e0c209e SL |
903 | // Register crate now to avoid double-reading metadata |
904 | creader.register_crate(&None, | |
905 | &self.ident, | |
906 | &self.name, | |
907 | self.span, | |
908 | library, | |
909 | true); | |
e9174d1e | 910 | } |
9e0c209e | 911 | } |
e9174d1e | 912 | |
9e0c209e SL |
913 | impl<'a> CrateLoader<'a> { |
914 | pub fn new(sess: &'a Session, cstore: &'a CStore, krate: &ast::Crate, crate_name: &str) | |
915 | -> Self { | |
916 | let loader = CrateLoader { | |
917 | sess: sess, | |
918 | cstore: cstore, | |
919 | creader: CrateReader::new(sess, cstore, crate_name, krate.config.clone()), | |
920 | }; | |
e9174d1e | 921 | |
9e0c209e SL |
922 | for attr in krate.attrs.iter().filter(|m| m.name() == "link_args") { |
923 | if let Some(ref linkarg) = attr.value_str() { | |
924 | loader.cstore.add_used_link_args(&linkarg); | |
e9174d1e | 925 | } |
e9174d1e | 926 | } |
9e0c209e SL |
927 | |
928 | loader | |
e9174d1e SL |
929 | } |
930 | ||
a7813a04 | 931 | fn process_foreign_mod(&mut self, i: &ast::Item, fm: &ast::ForeignMod) { |
7453a54e | 932 | if fm.abi == Abi::Rust || fm.abi == Abi::RustIntrinsic || fm.abi == Abi::PlatformIntrinsic { |
e9174d1e SL |
933 | return; |
934 | } | |
935 | ||
936 | // First, add all of the custom #[link_args] attributes | |
937 | for m in i.attrs.iter().filter(|a| a.check_name("link_args")) { | |
938 | if let Some(linkarg) = m.value_str() { | |
92a42be0 | 939 | self.cstore.add_used_link_args(&linkarg); |
e9174d1e SL |
940 | } |
941 | } | |
942 | ||
943 | // Next, process all of the #[link(..)]-style arguments | |
944 | for m in i.attrs.iter().filter(|a| a.check_name("link")) { | |
945 | let items = match m.meta_item_list() { | |
946 | Some(item) => item, | |
947 | None => continue, | |
948 | }; | |
949 | let kind = items.iter().find(|k| { | |
950 | k.check_name("kind") | |
951 | }).and_then(|a| a.value_str()); | |
952 | let kind = match kind.as_ref().map(|s| &s[..]) { | |
953 | Some("static") => cstore::NativeStatic, | |
954 | Some("dylib") => cstore::NativeUnknown, | |
955 | Some("framework") => cstore::NativeFramework, | |
956 | Some(k) => { | |
9e0c209e SL |
957 | struct_span_err!(self.sess, m.span, E0458, |
958 | "unknown kind: `{}`", k) | |
959 | .span_label(m.span, &format!("unknown kind")).emit(); | |
e9174d1e SL |
960 | cstore::NativeUnknown |
961 | } | |
962 | None => cstore::NativeUnknown | |
963 | }; | |
964 | let n = items.iter().find(|n| { | |
965 | n.check_name("name") | |
966 | }).and_then(|a| a.value_str()); | |
967 | let n = match n { | |
968 | Some(n) => n, | |
969 | None => { | |
9e0c209e SL |
970 | struct_span_err!(self.sess, m.span, E0459, |
971 | "#[link(...)] specified without `name = \"foo\"`") | |
972 | .span_label(m.span, &format!("missing `name` argument")).emit(); | |
e9174d1e SL |
973 | InternedString::new("foo") |
974 | } | |
975 | }; | |
92a42be0 | 976 | register_native_lib(self.sess, self.cstore, Some(m.span), n.to_string(), kind); |
e9174d1e SL |
977 | } |
978 | ||
979 | // Finally, process the #[linked_from = "..."] attribute | |
980 | for m in i.attrs.iter().filter(|a| a.check_name("linked_from")) { | |
981 | let lib_name = match m.value_str() { | |
982 | Some(name) => name, | |
983 | None => continue, | |
984 | }; | |
985 | let list = self.creader.foreign_item_map.entry(lib_name.to_string()) | |
986 | .or_insert(Vec::new()); | |
987 | list.extend(fm.items.iter().map(|it| it.id)); | |
988 | } | |
989 | } | |
223e47cc | 990 | } |
c34b1796 | 991 | |
9e0c209e SL |
992 | impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { |
993 | fn postprocess(&mut self, krate: &ast::Crate) { | |
994 | self.creader.inject_allocator_crate(); | |
995 | self.creader.inject_panic_runtime(krate); | |
c34b1796 | 996 | |
9e0c209e SL |
997 | if log_enabled!(log::INFO) { |
998 | dump_crates(&self.cstore); | |
c34b1796 | 999 | } |
c34b1796 | 1000 | |
9e0c209e SL |
1001 | for &(ref name, kind) in &self.sess.opts.libs { |
1002 | register_native_lib(self.sess, self.cstore, None, name.clone(), kind); | |
c34b1796 | 1003 | } |
9e0c209e SL |
1004 | self.creader.register_statically_included_foreign_items(); |
1005 | } | |
c34b1796 | 1006 | |
9e0c209e SL |
1007 | fn process_item(&mut self, item: &ast::Item, definitions: &hir_map::Definitions) { |
1008 | match item.node { | |
1009 | ast::ItemKind::ExternCrate(_) => {} | |
1010 | ast::ItemKind::ForeignMod(ref fm) => return self.process_foreign_mod(item, fm), | |
1011 | _ => return, | |
c34b1796 AL |
1012 | } |
1013 | ||
9e0c209e SL |
1014 | // If this `extern crate` item has `#[macro_use]` then we can safely skip it. |
1015 | // These annotations were processed during macro expansion and are already loaded | |
1016 | // (if necessary) into our crate store. | |
1017 | // | |
1018 | // Note that it's important we *don't* fall through below as some `#[macro_use]` | |
1019 | // crates are explicitly not linked (e.g. macro crates) so we want to ensure | |
1020 | // we avoid `resolve_crate` with those. | |
1021 | if attr::contains_name(&item.attrs, "macro_use") { | |
1022 | if self.cstore.was_used_for_derive_macros(item) { | |
1023 | return | |
c34b1796 AL |
1024 | } |
1025 | } | |
1026 | ||
9e0c209e SL |
1027 | if let Some(info) = self.creader.extract_crate_info(item) { |
1028 | if !info.should_link { | |
1029 | return; | |
1030 | } | |
c34b1796 | 1031 | |
9e0c209e SL |
1032 | let (cnum, ..) = self.creader.resolve_crate( |
1033 | &None, &info.ident, &info.name, None, item.span, PathKind::Crate, true, | |
1034 | ); | |
c34b1796 | 1035 | |
9e0c209e SL |
1036 | let def_id = definitions.opt_local_def_id(item.id).unwrap(); |
1037 | let len = definitions.def_path(def_id.index).data.len(); | |
1038 | ||
1039 | let extern_crate = | |
1040 | ExternCrate { def_id: def_id, span: item.span, direct: true, path_len: len }; | |
1041 | self.creader.update_extern_crate(cnum, extern_crate, &mut FnvHashSet()); | |
1042 | ||
1043 | self.cstore.add_extern_mod_stmt_cnum(info.id, cnum); | |
c34b1796 | 1044 | } |
9e0c209e | 1045 | } |
c34b1796 | 1046 | |
9e0c209e SL |
1047 | fn load_macros(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec<LoadedMacro> { |
1048 | macro_import::load_macros(self, extern_crate, allows_macros) | |
c34b1796 AL |
1049 | } |
1050 | } |