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