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/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 9b1ea3b4c4cf5..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}; @@ -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::(); 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 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/crateresolve1.rs b/src/test/ui/crate-loading/crateresolve1.rs index 49e47dacc3def..f4795e9536af7 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 0000000000000..0d7538eafd812 --- /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 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..afd3702de7f73 --- /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 0000000000000..969115a7d9774 --- /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 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 ce169867b7b1d..6d3e470bf43ca 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. //