about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_metadata/locator.rs44
-rw-r--r--src/test/ui/rmeta-rpass.rs9
2 files changed, 45 insertions, 8 deletions
diff --git a/src/librustc_metadata/locator.rs b/src/librustc_metadata/locator.rs
index 578216454f9..2157b8ce159 100644
--- a/src/librustc_metadata/locator.rs
+++ b/src/librustc_metadata/locator.rs
@@ -654,14 +654,36 @@ impl<'a> CrateLocator<'a> {
         dylibs: FxHashMap<PathBuf, PathKind>,
     ) -> Option<(Svh, Library)> {
         let mut slot = None;
+        // Order here matters, rmeta should come first. See comment in
+        // `extract_one` below.
         let source = CrateSource {
-            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
             rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot),
+            rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot),
             dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot),
         };
         slot.map(|(svh, metadata)| (svh, Library { source, metadata }))
     }
 
+    fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool {
+        if flavor == CrateFlavor::Dylib && self.is_proc_macro == Some(true) {
+            return true;
+        }
+
+        // The all loop is because `--crate-type=rlib --crate-type=rlib` is
+        // legal and produces both inside this type.
+        let is_rlib = self.sess.crate_types.borrow().iter().all(|c| *c == config::CrateType::Rlib);
+        let needs_object_code = self.sess.opts.output_types.should_codegen();
+        // If we're producing an rlib, then we don't need object code.
+        // Or, if we're not producing object code, then we don't need it either
+        // (e.g., if we're a cdylib but emitting just metadata).
+        if is_rlib || !needs_object_code {
+            flavor == CrateFlavor::Rmeta
+        } else {
+            // we need all flavors (perhaps not true, but what we do for now)
+            true
+        }
+    }
+
     // Attempts to extract *one* library from the set `m`. If the set has no
     // elements, `None` is returned. If the set has more than one element, then
     // the errors and notes are emitted about the set of libraries.
@@ -679,12 +701,22 @@ impl<'a> CrateLocator<'a> {
         let mut ret: Option<(PathBuf, PathKind)> = None;
         let mut error = 0;
 
+        // If we are producing an rlib, and we've already loaded metadata, then
+        // we should not attempt to discover further crate sources (unless we're
+        // locating a proc macro; exact logic is in needs_crate_flavor). This means
+        // that under -Zbinary-dep-depinfo we will not emit a dependency edge on
+        // the *unused* rlib, and by returning `None` here immediately we
+        // guarantee that we do indeed not use it.
+        //
+        // See also #68149 which provides more detail on why emitting the
+        // dependency on the rlib is a bad thing.
+        //
+        // We currenty do not verify that these other sources are even in sync,
+        // and this is arguably a bug (see #10786), but because reading metadata
+        // is quite slow (especially from dylibs) we currently do not read it
+        // from the other crate sources.
         if slot.is_some() {
-            // FIXME(#10786): for an optimization, we only read one of the
-            //                libraries' metadata sections. In theory we should
-            //                read both, but reading dylib metadata is quite
-            //                slow.
-            if m.is_empty() {
+            if m.is_empty() || !self.needs_crate_flavor(flavor) {
                 return None;
             } else if m.len() == 1 {
                 return Some(m.into_iter().next().unwrap());
diff --git a/src/test/ui/rmeta-rpass.rs b/src/test/ui/rmeta-rpass.rs
index 5a63b5b8598..173a6a394eb 100644
--- a/src/test/ui/rmeta-rpass.rs
+++ b/src/test/ui/rmeta-rpass.rs
@@ -1,6 +1,11 @@
 // run-pass
 // Test that using rlibs and rmeta dep crates work together. Specifically, that
-// there can be both an rmeta and an rlib file and rustc will prefer the rlib.
+// there can be both an rmeta and an rlib file and rustc will prefer the rmeta
+// file.
+//
+// This behavior is simply making sure this doesn't accidentally change; in this
+// case we want to make sure that the rlib isn't being used as that would cause
+// bugs in -Zbinary-dep-depinfo (see #68298).
 
 // aux-build:rmeta-rmeta.rs
 // aux-build:rmeta-rlib-rpass.rs
@@ -9,5 +14,5 @@ extern crate rmeta_aux;
 use rmeta_aux::Foo;
 
 pub fn main() {
-    let _ = Foo { field: 42 };
+    let _ = Foo { field2: 42 };
 }