]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_metadata/src/creader.rs
Rollup merge of #107700 - jyn514:tools-builder, r=Mark-Simulacrum
[rust.git] / compiler / rustc_metadata / src / creader.rs
index 653f2b39d3e74f646e22b01133ff4afe25f29bf4..bf8b8aa2ce49704e13d47567f016d7ad2535e97b 100644 (file)
@@ -1,10 +1,6 @@
 //! Validates all used crates and extern libraries and loads their metadata
 
-use crate::errors::{
-    ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
-    GlobalAllocRequired, NoMultipleAllocErrorHandler, NoMultipleGlobalAlloc, NoPanicStrategy,
-    NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
-};
+use crate::errors;
 use crate::locator::{CrateError, CrateLocator, CratePaths};
 use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
 
@@ -33,6 +29,7 @@
 use proc_macro::bridge::client::ProcMacro;
 use std::ops::Fn;
 use std::path::Path;
+use std::time::Duration;
 use std::{cmp, env};
 
 #[derive(Clone)]
@@ -359,7 +356,12 @@ fn verify_no_symbol_conflicts(&self, root: &CrateRoot) -> Result<(), CrateError>
         for (_, other) in self.cstore.iter_crate_data() {
             // Same stable crate id but different SVH
             if other.stable_crate_id() == root.stable_crate_id() && other.hash() != root.hash() {
-                return Err(CrateError::SymbolConflictsOthers(root.name()));
+                bug!(
+                    "Previously returned E0523 here. \
+                     See https://github.com/rust-lang/rust/pull/100599 for additional discussion.\
+                     root.name() = {}.",
+                    root.name()
+                );
             }
         }
 
@@ -689,8 +691,7 @@ fn dlsym_proc_macros(
     ) -> Result<&'static [ProcMacro], CrateError> {
         // Make sure the path contains a / or the linker will search for it.
         let path = env::current_dir().unwrap().join(path);
-        let lib = unsafe { libloading::Library::new(path) }
-            .map_err(|err| CrateError::DlOpen(err.to_string()))?;
+        let lib = load_dylib(&path, 5).map_err(|err| CrateError::DlOpen(err))?;
 
         let sym_name = self.sess.generate_proc_macro_decls_symbol(stable_crate_id);
         let sym = unsafe { lib.get::<*const &[ProcMacro]>(sym_name.as_bytes()) }
@@ -768,10 +769,11 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) {
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.sess.emit_err(CrateNotPanicRuntime { crate_name: name });
+            self.sess.emit_err(errors::CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.sess.emit_err(NoPanicStrategy { crate_name: name, strategy: desired_strategy });
+            self.sess
+                .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
         self.cstore.injected_panic_runtime = Some(cnum);
@@ -791,7 +793,7 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
         if name == sym::profiler_builtins && self.sess.contains_name(&krate.attrs, sym::no_core) {
-            self.sess.emit_err(ProfilerBuiltinsNeedsCore);
+            self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
         }
 
         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { return; };
@@ -799,21 +801,22 @@ fn inject_profiler_runtime(&mut self, krate: &ast::Crate) {
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.sess.emit_err(NotProfilerRuntime { crate_name: name });
+            self.sess.emit_err(errors::NotProfilerRuntime { crate_name: name });
         }
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
             [span1, span2, ..] => {
-                self.sess.emit_err(NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
+                self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
         };
         self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
             [span1, span2, ..] => {
-                self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+                self.sess
+                    .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
@@ -849,7 +852,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.sess.emit_err(ConflictingGlobalAlloc {
+                        self.sess.emit_err(errors::ConflictingGlobalAlloc {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -864,7 +867,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if data.has_alloc_error_handler() {
                 match alloc_error_handler {
                     Some(other_crate) => {
-                        self.sess.emit_err(ConflictingAllocErrorHandler {
+                        self.sess.emit_err(errors::ConflictingAllocErrorHandler {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -884,7 +887,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
             if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
                 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
-                self.sess.emit_err(GlobalAllocRequired);
+                self.sess.emit_err(errors::GlobalAllocRequired);
             }
             self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
@@ -917,7 +920,7 @@ fn inject_dependency_if(
         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
             let data = self.cstore.get_crate_data(dep);
             if needs_dep(&data) {
-                self.sess.emit_err(NoTransitiveNeedsDep {
+                self.sess.emit_err(errors::NoTransitiveNeedsDep {
                     crate_name: self.cstore.get_crate_data(krate).name(),
                     needs_crate_name: what,
                     deps_crate_name: data.name(),
@@ -1093,3 +1096,41 @@ fn visit_item(&mut self, item: &'ast ast::Item) {
     visit::walk_crate(&mut f, krate);
     f.spans
 }
+
+// On Windows the compiler would sometimes intermittently fail to open the
+// proc-macro DLL with `Error::LoadLibraryExW`. It is suspected that something in the
+// system still holds a lock on the file, so we retry a few times before calling it
+// an error.
+fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, String> {
+    assert!(max_attempts > 0);
+
+    let mut last_error = None;
+
+    for attempt in 0..max_attempts {
+        match unsafe { libloading::Library::new(&path) } {
+            Ok(lib) => {
+                if attempt > 0 {
+                    debug!(
+                        "Loaded proc-macro `{}` after {} attempts.",
+                        path.display(),
+                        attempt + 1
+                    );
+                }
+                return Ok(lib);
+            }
+            Err(err) => {
+                // Only try to recover from this specific error.
+                if !matches!(err, libloading::Error::LoadLibraryExW { .. }) {
+                    return Err(err.to_string());
+                }
+
+                last_error = Some(err);
+                std::thread::sleep(Duration::from_millis(100));
+                debug!("Failed to load proc-macro `{}`. Retrying.", path.display());
+            }
+        }
+    }
+
+    debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
+    Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts))
+}