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