Skip to content

Commit 6b7fc94

Browse files
authored
Rollup merge of rust-lang#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]: rust-lang#88675 (comment) cc `@Mark-Simulacrum` `@jyn514`
2 parents e1d9e31 + 8aa417c commit 6b7fc94

File tree

16 files changed

+130
-19
lines changed

16 files changed

+130
-19
lines changed

compiler/rustc_error_codes/src/error_codes.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ E0455: include_str!("./error_codes/E0455.md"),
237237
E0458: include_str!("./error_codes/E0458.md"),
238238
E0459: include_str!("./error_codes/E0459.md"),
239239
E0463: include_str!("./error_codes/E0463.md"),
240+
E0464: include_str!("./error_codes/E0464.md"),
240241
E0466: include_str!("./error_codes/E0466.md"),
241242
E0468: include_str!("./error_codes/E0468.md"),
242243
E0469: include_str!("./error_codes/E0469.md"),
@@ -586,7 +587,6 @@ E0785: include_str!("./error_codes/E0785.md"),
586587
E0460, // found possibly newer version of crate `..`
587588
E0461, // couldn't find crate `..` with expected target triple ..
588589
E0462, // found staticlib `..` instead of rlib or dylib
589-
E0464, // multiple matching crates for `..`
590590
E0465, // multiple .. candidates for `..` found
591591
// E0467, removed
592592
// E0470, removed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
The compiler found multiple library files with the requested crate name.
2+
3+
This error can occur in several different cases -- for example, when using
4+
`extern crate` or passing `--extern` options without crate paths. It can also be
5+
caused by caching issues with the build directory, in which case `cargo clean`
6+
may help.

compiler/rustc_metadata/src/locator.rs

+21-13
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ use rustc_span::Span;
232232
use rustc_target::spec::{Target, TargetTriple};
233233

234234
use snap::read::FrameDecoder;
235+
use std::fmt::Write as _;
235236
use std::io::{Read, Result as IoResult, Write};
236237
use std::path::{Path, PathBuf};
237238
use std::{cmp, fmt, fs};
@@ -910,23 +911,30 @@ impl CrateError {
910911
"multiple matching crates for `{}`",
911912
crate_name
912913
);
914+
let mut libraries: Vec<_> = libraries.into_values().collect();
915+
// Make ordering of candidates deterministic.
916+
// This has to `clone()` to work around lifetime restrictions with `sort_by_key()`.
917+
// `sort_by()` could be used instead, but this is in the error path,
918+
// so the performance shouldn't matter.
919+
libraries.sort_by_cached_key(|lib| lib.source.paths().next().unwrap().clone());
913920
let candidates = libraries
914921
.iter()
915-
.filter_map(|(_, lib)| {
922+
.map(|lib| {
916923
let crate_name = &lib.metadata.get_root().name().as_str();
917-
match (&lib.source.dylib, &lib.source.rlib) {
918-
(Some((pd, _)), Some((pr, _))) => Some(format!(
919-
"\ncrate `{}`: {}\n{:>padding$}",
920-
crate_name,
921-
pd.display(),
922-
pr.display(),
923-
padding = 8 + crate_name.len()
924-
)),
925-
(Some((p, _)), None) | (None, Some((p, _))) => {
926-
Some(format!("\ncrate `{}`: {}", crate_name, p.display()))
927-
}
928-
(None, None) => None,
924+
let mut paths = lib.source.paths();
925+
926+
// This `unwrap()` should be okay because there has to be at least one
927+
// source file. `CrateSource`'s docs confirm that too.
928+
let mut s = format!(
929+
"\ncrate `{}`: {}",
930+
crate_name,
931+
paths.next().unwrap().display()
932+
);
933+
let padding = 8 + crate_name.len();
934+
for path in paths {
935+
write!(s, "\n{:>padding$}", path.display(), padding = padding).unwrap();
929936
}
937+
s
930938
})
931939
.collect::<String>();
932940
err.note(&format!("candidates:{}", candidates));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-1 --emit=metadata
2+
#![crate_name = "crateresolve2"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 10 }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-2 --emit=metadata
2+
#![crate_name = "crateresolve2"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 20 }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-3 --emit=metadata
2+
#![crate_name = "crateresolve2"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 30 }
+4-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
// dont-check-compiler-stderr
21
// aux-build:crateresolve1-1.rs
32
// aux-build:crateresolve1-2.rs
43
// aux-build:crateresolve1-3.rs
5-
// error-pattern:multiple matching crates for `crateresolve1`
4+
5+
// normalize-stderr-test: "\.so" -> ".dylib"
6+
// normalize-stderr-test: "\.dll" -> ".dylib"
67

78
extern crate crateresolve1;
9+
//~^ ERROR multiple matching crates for `crateresolve1`
810

911
fn main() {
1012
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0464]: multiple matching crates for `crateresolve1`
2+
--> $DIR/crateresolve1.rs:8:1
3+
|
4+
LL | extern crate crateresolve1;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: candidates:
8+
crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-1.dylib
9+
crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-2.dylib
10+
crate `crateresolve1`: $TEST_BUILD_DIR/crate-loading/crateresolve1/auxiliary/libcrateresolve1-3.dylib
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0464`.
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// check-fail
2+
3+
// aux-build:crateresolve2-1.rs
4+
// aux-build:crateresolve2-2.rs
5+
// aux-build:crateresolve2-3.rs
6+
7+
extern crate crateresolve2;
8+
//~^ ERROR multiple matching crates for `crateresolve2`
9+
10+
fn main() {
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0464]: multiple matching crates for `crateresolve2`
2+
--> $DIR/crateresolve2.rs:7:1
3+
|
4+
LL | extern crate crateresolve2;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: candidates:
8+
crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-1.rmeta
9+
crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-2.rmeta
10+
crate `crateresolve2`: $TEST_BUILD_DIR/crate-loading/crateresolve2/auxiliary/libcrateresolve2-3.rmeta
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0464`.

src/test/ui/error-codes/E0464.rs

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// aux-build:crateresolve1-1.rs
2+
// aux-build:crateresolve1-2.rs
3+
// aux-build:crateresolve1-3.rs
4+
5+
// normalize-stderr-test: "\.so" -> ".dylib"
6+
// normalize-stderr-test: "\.dll" -> ".dylib"
7+
8+
extern crate crateresolve1;
9+
//~^ ERROR multiple matching crates for `crateresolve1`
10+
11+
fn main() {
12+
}

src/test/ui/error-codes/E0464.stderr

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0464]: multiple matching crates for `crateresolve1`
2+
--> $DIR/E0464.rs:8:1
3+
|
4+
LL | extern crate crateresolve1;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: candidates:
8+
crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-1.dylib
9+
crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-2.dylib
10+
crate `crateresolve1`: $TEST_BUILD_DIR/error-codes/E0464/auxiliary/libcrateresolve1-3.dylib
11+
12+
error: aborting due to previous error
13+
14+
For more information about this error, try `rustc --explain E0464`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-1
2+
#![crate_name = "crateresolve1"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 10 }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-2
2+
#![crate_name = "crateresolve1"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 20 }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// compile-flags:-C extra-filename=-3
2+
#![crate_name = "crateresolve1"]
3+
#![crate_type = "lib"]
4+
5+
pub fn f() -> isize { 30 }

src/tools/tidy/src/error_codes_check.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ use regex::Regex;
1010

1111
// A few of those error codes can't be tested but all the others can and *should* be tested!
1212
const EXEMPTED_FROM_TEST: &[&str] = &[
13-
"E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0464", "E0465", "E0476",
14-
"E0482", "E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
13+
"E0227", "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0482",
14+
"E0514", "E0519", "E0523", "E0554", "E0640", "E0717", "E0729",
1515
];
1616

1717
// Some error codes don't have any tests apparently...
18-
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"];
18+
const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602", "E0729"];
1919

2020
// If the file path contains any of these, we don't want to try to extract error codes from it.
2121
//

0 commit comments

Comments
 (0)