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