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