From 6792c6a8510640dcdf7b6e82dc9c35d39dbf4226 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 6 Oct 2021 10:16:02 -0700 Subject: [PATCH 1/6] Sort candidate libraries by source path in error This makes the error output deterministic and thus testable. --- compiler/rustc_metadata/src/locator.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 9b1ea3b4c4cf5..f1ada3e1b7542 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -910,9 +910,15 @@ 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)| { + .filter_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!( From 642a43a9cd729bf2a7d20d34216cfee02c1c1e33 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 5 Oct 2021 20:23:40 -0700 Subject: [PATCH 2/6] Test crate loading error stderr And remove E0464 from test-exemption list, since it now has a full test. --- src/test/ui/crate-loading/crateresolve1.rs | 7 +++++-- src/test/ui/crate-loading/crateresolve1.stderr | 13 +++++++++++++ src/tools/tidy/src/error_codes_check.rs | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) create mode 100644 src/test/ui/crate-loading/crateresolve1.stderr diff --git a/src/test/ui/crate-loading/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs index 49e47dacc3def..8e01862746f53 100644 --- a/src/test/ui/crate-loading/crateresolve1.rs +++ b/src/test/ui/crate-loading/crateresolve1.rs @@ -1,10 +1,13 @@ -// 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: "libcrateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$1.somelib" 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 0000000000000..1cae13922d6be --- /dev/null +++ b/src/test/ui/crate-loading/crateresolve1.stderr @@ -0,0 +1,13 @@ +error[E0464]: multiple matching crates for `crateresolve1` + --> $DIR/crateresolve1.rs:9: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 + diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index ce169867b7b1d..6d802cdcd03a6 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -10,8 +10,8 @@ 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... From ad49cb6e0c7346bd9ee551f7940a267e1712a439 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 5 Oct 2021 20:40:24 -0700 Subject: [PATCH 3/6] Add test for showing rmeta candidates in error --- .../ui/crate-loading/auxiliary/crateresolve2-1.rs | 5 +++++ .../ui/crate-loading/auxiliary/crateresolve2-2.rs | 5 +++++ .../ui/crate-loading/auxiliary/crateresolve2-3.rs | 5 +++++ src/test/ui/crate-loading/crateresolve2.rs | 14 ++++++++++++++ src/test/ui/crate-loading/crateresolve2.stderr | 10 ++++++++++ 5 files changed, 39 insertions(+) create mode 100644 src/test/ui/crate-loading/auxiliary/crateresolve2-1.rs create mode 100644 src/test/ui/crate-loading/auxiliary/crateresolve2-2.rs create mode 100644 src/test/ui/crate-loading/auxiliary/crateresolve2-3.rs create mode 100644 src/test/ui/crate-loading/crateresolve2.rs create mode 100644 src/test/ui/crate-loading/crateresolve2.stderr 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 0000000000000..e9459ed0719fd --- /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 0000000000000..c4541682723b8 --- /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 0000000000000..b356db4b6fc31 --- /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/crateresolve2.rs b/src/test/ui/crate-loading/crateresolve2.rs new file mode 100644 index 0000000000000..5a4fee7ed6afa --- /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 0000000000000..9a8ef6f2a6003 --- /dev/null +++ b/src/test/ui/crate-loading/crateresolve2.stderr @@ -0,0 +1,10 @@ +error[E0464]: multiple matching crates for `crateresolve2` + --> $DIR/crateresolve2.rs:10:1 + | +LL | extern crate crateresolve2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: candidates: + +error: aborting due to previous error + From 2e56b6f98e34edcafe0d7691939c4c33302a1a5c Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 5 Oct 2021 19:43:44 -0700 Subject: [PATCH 4/6] 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()`. [1]: https://github.com/rust-lang/rust/pull/88675#issuecomment-935282436 --- compiler/rustc_metadata/src/locator.rs | 28 ++++++++++--------- .../ui/crate-loading/crateresolve2.stderr | 3 ++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index f1ada3e1b7542..c54ea61060271 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}; @@ -918,21 +919,22 @@ impl CrateError { 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::(); err.note(&format!("candidates:{}", candidates)); diff --git a/src/test/ui/crate-loading/crateresolve2.stderr b/src/test/ui/crate-loading/crateresolve2.stderr index 9a8ef6f2a6003..c6da629df2781 100644 --- a/src/test/ui/crate-loading/crateresolve2.stderr +++ b/src/test/ui/crate-loading/crateresolve2.stderr @@ -5,6 +5,9 @@ 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 From cc6a09009d5129f1221dc0e93c08c84967d1015e Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 6 Oct 2021 13:01:43 -0700 Subject: [PATCH 5/6] Add long explanation for E0464 The test is copied from `src/test/ui/crate-loading/crateresolve1.rs` and its auxiliary tests. I added it to the `compile_fail` code example check exemption list since it's hard if not impossible to reproduce this error in a standalone code example. --- compiler/rustc_error_codes/src/error_codes.rs | 2 +- .../rustc_error_codes/src/error_codes/E0464.md | 6 ++++++ src/test/ui/crate-loading/crateresolve1.rs | 2 ++ src/test/ui/crate-loading/crateresolve1.stderr | 3 ++- src/test/ui/crate-loading/crateresolve2.stderr | 1 + src/test/ui/error-codes/E0464.rs | 15 +++++++++++++++ src/test/ui/error-codes/E0464.stderr | 14 ++++++++++++++ .../ui/error-codes/auxiliary/crateresolve1-1.rs | 5 +++++ .../ui/error-codes/auxiliary/crateresolve1-2.rs | 5 +++++ .../ui/error-codes/auxiliary/crateresolve1-3.rs | 5 +++++ src/tools/tidy/src/error_codes_check.rs | 2 +- 11 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 compiler/rustc_error_codes/src/error_codes/E0464.md create mode 100644 src/test/ui/error-codes/E0464.rs create mode 100644 src/test/ui/error-codes/E0464.stderr create mode 100644 src/test/ui/error-codes/auxiliary/crateresolve1-1.rs create mode 100644 src/test/ui/error-codes/auxiliary/crateresolve1-2.rs create mode 100644 src/test/ui/error-codes/auxiliary/crateresolve1-3.rs diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs index 1b4b58314b356..27b2bfbaf4744 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 0000000000000..9108d856c9d77 --- /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/src/test/ui/crate-loading/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs index 8e01862746f53..c071a9b4b6ac4 100644 --- a/src/test/ui/crate-loading/crateresolve1.rs +++ b/src/test/ui/crate-loading/crateresolve1.rs @@ -6,6 +6,8 @@ // normalize-stderr-test: "\\\?\\" -> "" // normalize-stderr-test: "libcrateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$1.somelib" +// NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`. + extern crate crateresolve1; //~^ ERROR multiple matching crates for `crateresolve1` diff --git a/src/test/ui/crate-loading/crateresolve1.stderr b/src/test/ui/crate-loading/crateresolve1.stderr index 1cae13922d6be..0d7538eafd812 100644 --- a/src/test/ui/crate-loading/crateresolve1.stderr +++ b/src/test/ui/crate-loading/crateresolve1.stderr @@ -1,5 +1,5 @@ error[E0464]: multiple matching crates for `crateresolve1` - --> $DIR/crateresolve1.rs:9:1 + --> $DIR/crateresolve1.rs:11:1 | LL | extern crate crateresolve1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -11,3 +11,4 @@ LL | extern crate crateresolve1; 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.stderr b/src/test/ui/crate-loading/crateresolve2.stderr index c6da629df2781..afd3702de7f73 100644 --- a/src/test/ui/crate-loading/crateresolve2.stderr +++ b/src/test/ui/crate-loading/crateresolve2.stderr @@ -11,3 +11,4 @@ LL | extern crate crateresolve2; 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 0000000000000..831f32116a58d --- /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: "libcrateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$1.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 0000000000000..3d950ddd28ee0 --- /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 0000000000000..a00a19e46d519 --- /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 0000000000000..71cc0a12ea379 --- /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 0000000000000..921687d4c3bff --- /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 6d802cdcd03a6..6d3e470bf43ca 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -15,7 +15,7 @@ const EXEMPTED_FROM_TEST: &[&str] = &[ ]; // 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. // From bf2d2e559725d57bcc225e1950f228478e06d52b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 12 Oct 2021 13:30:15 -0700 Subject: [PATCH 6/6] Work around different filenames for DLLs --- src/test/ui/crate-loading/crateresolve1.rs | 2 +- src/test/ui/error-codes/E0464.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/crate-loading/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs index c071a9b4b6ac4..f4795e9536af7 100644 --- a/src/test/ui/crate-loading/crateresolve1.rs +++ b/src/test/ui/crate-loading/crateresolve1.rs @@ -4,7 +4,7 @@ // normalize-stderr-test: "\.nll/" -> "/" // normalize-stderr-test: "\\\?\\" -> "" -// normalize-stderr-test: "libcrateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$1.somelib" +// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib" // NOTE: This test is duplicated at `src/test/ui/error-codes/E0464.rs`. diff --git a/src/test/ui/error-codes/E0464.rs b/src/test/ui/error-codes/E0464.rs index 831f32116a58d..969115a7d9774 100644 --- a/src/test/ui/error-codes/E0464.rs +++ b/src/test/ui/error-codes/E0464.rs @@ -4,7 +4,7 @@ // normalize-stderr-test: "\.nll/" -> "/" // normalize-stderr-test: "\\\?\\" -> "" -// normalize-stderr-test: "libcrateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$1.somelib" +// normalize-stderr-test: "(lib)?crateresolve1-([123])\.[a-z]+" -> "libcrateresolve1-$2.somelib" // NOTE: This test is duplicated from `src/test/ui/crate-loading/crateresolve1.rs`.