about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-10-13 10:38:12 +0000
committerbors <bors@rust-lang.org>2021-10-13 10:38:12 +0000
commit5728bd64b49b0e78d0180efed75ef0870ae60266 (patch)
tree971aa79ac6cdd03061cb6ea2130f28381b03d61f
parenta16f686e4a0ea15dcd3b5aa3db7b1cba27bb9453 (diff)
parentbf2d2e559725d57bcc225e1950f228478e06d52b (diff)
Auto merge of #89587 - camelid:all-candidates, r=petrochenkov
Include rmeta candidates in "multiple matching crates" error

Only dylib and rlib candidates were included in the error. I think the
reason is that at the time this error was originally implemented, rmeta
crate sources were represented different from dylib and rlib sources.
I wrote up more detailed analysis in [this comment][1].

The new version of the code is also a bit easier to read and should be
more robust to future changes since it uses `CrateSources::paths()`.

I also changed the code to sort the candidates to make the output deterministic;
added full stderr tests for the error; and added a long error code explanation.

[1]: https://github.com/rust-lang/rust/pull/88675#issuecomment-935282436

cc `@Mark-Simulacrum` `@jyn514`
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0464.md6
-rw-r--r--compiler/rustc_metadata/src/locator.rs34
-rw-r--r--src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs5
-rw-r--r--src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs5
-rw-r--r--src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs5
-rw-r--r--src/test/ui/crate-loading/crateresolve1.rs9
-rw-r--r--src/test/ui/crate-loading/crateresolve1.stderr14
-rw-r--r--src/test/ui/crate-loading/crateresolve2.rs14
-rw-r--r--src/test/ui/crate-loading/crateresolve2.stderr14
-rw-r--r--src/test/ui/error-codes/E0464.rs15
-rw-r--r--src/test/ui/error-codes/E0464.stderr14
-rw-r--r--src/test/ui/error-codes/auxiliary/crateresolve1-1.rs5
-rw-r--r--src/test/ui/error-codes/auxiliary/crateresolve1-2.rs5
-rw-r--r--src/test/ui/error-codes/auxiliary/crateresolve1-3.rs5
-rw-r--r--src/tools/tidy/src/error_codes_check.rs6
16 files changed, 139 insertions, 19 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 1b4b58314b3..27b2bfbaf47 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -237,6 +237,7 @@ E0455: include_str!("./error_codes/E0455.md"),
 E0458: include_str!("./error_codes/E0458.md"),
 E0459: include_str!("./error_codes/E0459.md"),
 E0463: include_str!("./error_codes/E0463.md"),
+E0464: include_str!("./error_codes/E0464.md"),
 E0466: include_str!("./error_codes/E0466.md"),
 E0468: include_str!("./error_codes/E0468.md"),
 E0469: include_str!("./error_codes/E0469.md"),
@@ -587,7 +588,6 @@ E0785: include_str!("./error_codes/E0785.md"),
     E0460, // found possibly newer version of crate `..`
     E0461, // couldn't find crate `..` with expected target triple ..
     E0462, // found staticlib `..` instead of rlib or dylib
-    E0464, // multiple matching crates for `..`
     E0465, // multiple .. candidates for `..` found
 //  E0467, removed
 //  E0470, removed
diff --git a/compiler/rustc_error_codes/src/error_codes/E0464.md b/compiler/rustc_error_codes/src/error_codes/E0464.md
new file mode 100644
index 00000000000..9108d856c9d
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0464.md
@@ -0,0 +1,6 @@
+The compiler found multiple library files with the requested crate name.
+
+This error can occur in several different cases -- for example, when using
+`extern crate` or passing `--extern` options without crate paths. It can also be
+caused by caching issues with the build directory, in which case `cargo clean`
+may help.
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 9b1ea3b4c4c..c54ea610602 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -232,6 +232,7 @@ use rustc_span::Span;
 use rustc_target::spec::{Target, TargetTriple};
 
 use snap::read::FrameDecoder;
+use std::fmt::Write as _;
 use std::io::{Read, Result as IoResult, Write};
 use std::path::{Path, PathBuf};
 use std::{cmp, fmt, fs};
@@ -910,23 +911,30 @@ impl CrateError {
                     "multiple matching crates for `{}`",
                     crate_name
                 );
+                let mut libraries: Vec<_> = libraries.into_values().collect();
+                // Make ordering of candidates deterministic.
+                // This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
+                // `sort_by()` could be used instead, but this is in the error path,
+                // so the performance shouldn't matter.
+                libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
                 let candidates = libraries
                     .iter()
-                    .filter_map(|(_, lib)| {
+                    .map(|lib| {
                         let crate_name = &lib.metadata.get_root().name().as_str();
-                        match (&lib.source.dylib, &lib.source.rlib) {
-                            (Some((pd, _)), Some((pr, _))) => Some(format!(
-                                "\ncrate `{}`: {}\n{:>padding$}",
-                                crate_name,
-                                pd.display(),
-                                pr.display(),
-                                padding = 8 + crate_name.len()
-                            )),
-                            (Some((p, _)), None) | (None, Some((p, _))) => {
-                                Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
-                            }
-                            (None, None) => None,
+                        let mut paths = lib.source.paths();
+
+                        // This `unwrap()` should be okay because there has to be at least one
+                        // source file. `CrateSource`'s docs confirm that too.
+                        let mut s = format!(
+                            "\ncrate `{}`: {}",
+                            crate_name,
+                            paths.next().unwrap().display()
+                        );
+                        let padding = 8 + crate_name.len();
+                        for path in paths {
+                            write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap();
                         }
+                        s
                     })
                     .collect::<String>();
                 err.note(&format!("candidates:{}", candidates));
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs b/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs
new file mode 100644
index 00000000000..e9459ed0719
--- /dev/null
+++ b/src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-1 --emit=metadata
+#![crate_name = "crateresolve2"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 10 }
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs b/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs
new file mode 100644
index 00000000000..c4541682723
--- /dev/null
+++ b/src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-2 --emit=metadata
+#![crate_name = "crateresolve2"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 20 }
diff --git a/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs b/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs
new file mode 100644
index 00000000000..b356db4b6fc
--- /dev/null
+++ b/src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-3 --emit=metadata
+#![crate_name = "crateresolve2"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 30 }
diff --git a/src/test/ui/crate-loading/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs
index 49e47dacc3d..f4795e9536a 100644
--- a/src/test/ui/crate-loading/crateresolve1.rs
+++ b/src/test/ui/crate-loading/crateresolve1.rs
@@ -1,10 +1,15 @@
-// dont-check-compiler-stderr
 // aux-build:crateresolve1-1.rs
 // aux-build:crateresolve1-2.rs
 // aux-build:crateresolve1-3.rs
-// error-pattern:multiple matching crates for `crateresolve1`
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib"
+
+// NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`.
 
 extern crate crateresolve1;
+//~^ ERROR multiple matching crates for `crateresolve1`
 
 fn main() {
 }
diff --git a/src/test/ui/crate-loading/crateresolve1.stderr b/src/test/ui/crate-loading/crateresolve1.stderr
new file mode 100644
index 00000000000..0d7538eafd8
--- /dev/null
+++ b/src/test/ui/crate-loading/crateresolve1.stderr
@@ -0,0 +1,14 @@
+error[E0464]: multiple matching crates for `crateresolve1`
+  --> $DIR/crateresolve1.rs:11:1
+   |
+LL | extern crate crateresolve1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: candidates:
+           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.somelib
+           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.somelib
+           crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.somelib
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
diff --git a/src/test/ui/crate-loading/crateresolve2.rs b/src/test/ui/crate-loading/crateresolve2.rs
new file mode 100644
index 00000000000..5a4fee7ed6a
--- /dev/null
+++ b/src/test/ui/crate-loading/crateresolve2.rs
@@ -0,0 +1,14 @@
+// check-fail
+
+// aux-build:crateresolve2-1.rs
+// aux-build:crateresolve2-2.rs
+// aux-build:crateresolve2-3.rs
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+
+extern crate crateresolve2;
+//~^ ERROR multiple matching crates for `crateresolve2`
+
+fn main() {
+}
diff --git a/src/test/ui/crate-loading/crateresolve2.stderr b/src/test/ui/crate-loading/crateresolve2.stderr
new file mode 100644
index 00000000000..afd3702de7f
--- /dev/null
+++ b/src/test/ui/crate-loading/crateresolve2.stderr
@@ -0,0 +1,14 @@
+error[E0464]: multiple matching crates for `crateresolve2`
+  --> $DIR/crateresolve2.rs:10:1
+   |
+LL | extern crate crateresolve2;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: candidates:
+           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
+           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
+           crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
diff --git a/src/test/ui/error-codes/E0464.rs b/src/test/ui/error-codes/E0464.rs
new file mode 100644
index 00000000000..969115a7d97
--- /dev/null
+++ b/src/test/ui/error-codes/E0464.rs
@@ -0,0 +1,15 @@
+// aux-build:crateresolve1-1.rs
+// aux-build:crateresolve1-2.rs
+// aux-build:crateresolve1-3.rs
+
+// normalize-stderr-test: "\.nll/" -> "/"
+// normalize-stderr-test: "\\\?\\" -> ""
+// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib"
+
+// NOTE: This test is duplicated from `src/test/ui/crate-loading/crateresolve1.rs`.
+
+extern crate crateresolve1;
+//~^ ERROR multiple matching crates for `crateresolve1`
+
+fn main() {
+}
diff --git a/src/test/ui/error-codes/E0464.stderr b/src/test/ui/error-codes/E0464.stderr
new file mode 100644
index 00000000000..3d950ddd28e
--- /dev/null
+++ b/src/test/ui/error-codes/E0464.stderr
@@ -0,0 +1,14 @@
+error[E0464]: multiple matching crates for `crateresolve1`
+  --> $DIR/E0464.rs:11:1
+   |
+LL | extern crate crateresolve1;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: candidates:
+           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.somelib
+           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.somelib
+           crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.somelib
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0464`.
diff --git a/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs b/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs
new file mode 100644
index 00000000000..a00a19e46d5
--- /dev/null
+++ b/src/test/ui/error-codes/auxiliary/crateresolve1-1.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-1
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 10 }
diff --git a/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs b/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs
new file mode 100644
index 00000000000..71cc0a12ea3
--- /dev/null
+++ b/src/test/ui/error-codes/auxiliary/crateresolve1-2.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-2
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 20 }
diff --git a/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs b/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs
new file mode 100644
index 00000000000..921687d4c3b
--- /dev/null
+++ b/src/test/ui/error-codes/auxiliary/crateresolve1-3.rs
@@ -0,0 +1,5 @@
+// compile-flags:-C extra-filename=-3
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize { 30 }
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index ce169867b7b..6d3e470bf43 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -10,12 +10,12 @@ use regex::Regex;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0464", "E0465", "E0476",
-    "E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514",
+    "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0729"];
 
 // If the file path contains any of these, we don't want to try to extract error codes from it.
 //