Skip to content

Commit

Permalink
Auto merge of #89587 - camelid:all-candidates, r=petrochenkov
Browse files Browse the repository at this point in the history
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]: #88675 (comment)

cc `@Mark-Simulacrum` `@jyn514`
  • Loading branch information
bors committed Oct 13, 2021
2 parents a16f686 + bf2d2e5 commit 5728bd6
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 19 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_error_codes/src/error_codes.rs
Expand Up @@ -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"),
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions 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.
34 changes: 21 additions & 13 deletions compiler/rustc_metadata/src/locator.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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));
Expand Down
5 changes: 5 additions & 0 deletions 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 }
5 changes: 5 additions & 0 deletions 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 }
5 changes: 5 additions & 0 deletions 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 }
9 changes: 7 additions & 2 deletions 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() {
}
14 changes: 14 additions & 0 deletions 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`.
14 changes: 14 additions & 0 deletions 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() {
}
14 changes: 14 additions & 0 deletions 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`.
15 changes: 15 additions & 0 deletions 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() {
}
14 changes: 14 additions & 0 deletions 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`.
5 changes: 5 additions & 0 deletions 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 }
5 changes: 5 additions & 0 deletions 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 }
5 changes: 5 additions & 0 deletions 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 }
6 changes: 3 additions & 3 deletions src/tools/tidy/src/error_codes_check.rs
Expand Up @@ -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.
//
Expand Down

0 comments on commit 5728bd6

Please sign in to comment.