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