diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 820f7ba4a6f23..dd497667a4d9f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -278,7 +278,7 @@ pub fn each_linked_rlib( } let crate_name = info.crate_name[&cnum]; let used_crate_source = &info.used_crate_source[&cnum]; - if let Some((path, _)) = &used_crate_source.rlib { + if let Some(path) = &used_crate_source.rlib { f(cnum, path); } else if used_crate_source.rmeta.is_some() { return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name }); @@ -542,7 +542,7 @@ fn link_staticlib( }; let crate_name = codegen_results.crate_info.crate_name[&cnum]; let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; - if let Some((path, _)) = &used_crate_source.dylib { + if let Some(path) = &used_crate_source.dylib { all_rust_dylibs.push(&**path); } else if used_crate_source.rmeta.is_some() { sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name }); @@ -620,7 +620,6 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out .used_crate_source .items() .filter_map(|(_, csource)| csource.rlib.as_ref()) - .map(|(path, _)| path) .into_sorted_stable_ord(); for input_rlib in input_rlibs { @@ -2178,12 +2177,7 @@ fn add_rpath_args( .crate_info .used_crates .iter() - .filter_map(|cnum| { - codegen_results.crate_info.used_crate_source[cnum] - .dylib - .as_ref() - .map(|(path, _)| &**path) - }) + .filter_map(|cnum| codegen_results.crate_info.used_crate_source[cnum].dylib.as_deref()) .collect::>(); let rpath_config = RPathConfig { libs: &*libs, @@ -2661,7 +2655,7 @@ fn add_native_libs_from_crate( if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() { // If rlib contains native libs as archives, unpack them to tmpdir. - let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0; + let rlib = codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap(); archive_builder_builder .extract_bundled_libs(rlib, tmpdir, bundled_libs) .unwrap_or_else(|e| sess.dcx().emit_fatal(e)); @@ -2832,7 +2826,7 @@ fn add_upstream_rust_crates( } Linkage::Dynamic => { let src = &codegen_results.crate_info.used_crate_source[&cnum]; - add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0); + add_dynamic_crate(cmd, sess, src.dylib.as_ref().unwrap()); } } @@ -2960,7 +2954,7 @@ fn add_static_crate( bundled_lib_file_names: &FxIndexSet, ) { let src = &codegen_results.crate_info.used_crate_source[&cnum]; - let cratepath = &src.rlib.as_ref().unwrap().0; + let cratepath = src.rlib.as_ref().unwrap(); let mut link_upstream = |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false); diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs index f0db9623b674e..c1a5c8ebc7645 100644 --- a/compiler/rustc_data_structures/src/fx.rs +++ b/compiler/rustc_data_structures/src/fx.rs @@ -1,6 +1,6 @@ use std::hash::BuildHasherDefault; -pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; +pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher}; pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index ddfec9f886a6a..b7273dd695614 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -684,19 +684,19 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P for &cnum in tcx.crates(()) { let source = tcx.used_crate_source(cnum); - if let Some((path, _)) = &source.dylib { + if let Some(path) = &source.dylib { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, )); } - if let Some((path, _)) = &source.rlib { + if let Some(path) = &source.rlib { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, )); } - if let Some((path, _)) = &source.rmeta { + if let Some(path) = &source.rmeta { files.extend(hash_iter_files( iter::once(escape_dep_filename(&path.display().to_string())), checksum_hash_algo, diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 4e2e1e21ec6dd..4400f9f68180e 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -135,16 +135,16 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { writeln!(fmt, " priv: {:?}", data.is_private_dep())?; let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source(); if let Some(dylib) = dylib { - writeln!(fmt, " dylib: {}", dylib.0.display())?; + writeln!(fmt, " dylib: {}", dylib.display())?; } if let Some(rlib) = rlib { - writeln!(fmt, " rlib: {}", rlib.0.display())?; + writeln!(fmt, " rlib: {}", rlib.display())?; } if let Some(rmeta) = rmeta { - writeln!(fmt, " rmeta: {}", rmeta.0.display())?; + writeln!(fmt, " rmeta: {}", rmeta.display())?; } if let Some(sdylib_interface) = sdylib_interface { - writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?; + writeln!(fmt, " sdylib interface: {}", sdylib_interface.display())?; } } Ok(()) @@ -514,73 +514,19 @@ impl CStore { } } - fn existing_match( - &self, - externs: &Externs, - name: Symbol, - hash: Option, - kind: PathKind, - ) -> Option { + fn existing_match(&self, name: Symbol, hash: Option) -> Option { + let hash = hash?; + for (cnum, data) in self.iter_crate_data() { if data.name() != name { trace!("{} did not match {}", data.name(), name); continue; } - match hash { - Some(hash) if hash == data.hash() => return Some(cnum), - Some(hash) => { - debug!("actual hash {} did not match expected {}", hash, data.hash()); - continue; - } - None => {} - } - - // When the hash is None we're dealing with a top-level dependency - // in which case we may have a specification on the command line for - // this library. Even though an upstream library may have loaded - // something of the same name, we have to make sure it was loaded - // from the exact same location as well. - // - // We're also sure to compare *paths*, not actual byte slices. The - // `source` stores paths which are normalized which may be different - // from the strings on the command line. - let source = data.source(); - if let Some(entry) = externs.get(name.as_str()) { - // Only use `--extern crate_name=path` here, not `--extern crate_name`. - if let Some(mut files) = entry.files() { - if files.any(|l| { - let l = l.canonicalized(); - source.dylib.as_ref().map(|(p, _)| p) == Some(l) - || source.rlib.as_ref().map(|(p, _)| p) == Some(l) - || source.rmeta.as_ref().map(|(p, _)| p) == Some(l) - }) { - return Some(cnum); - } - } - continue; - } - - // Alright, so we've gotten this far which means that `data` has the - // right name, we don't have a hash, and we don't have a --extern - // pointing for ourselves. We're still not quite yet done because we - // have to make sure that this crate was found in the crate lookup - // path (this is a top-level dependency) as we don't want to - // implicitly load anything inside the dependency lookup path. - let prev_kind = source - .dylib - .as_ref() - .or(source.rlib.as_ref()) - .or(source.rmeta.as_ref()) - .expect("No sources for crate") - .1; - if kind.matches(prev_kind) { + if hash == data.hash() { return Some(cnum); } else { - debug!( - "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}", - name, kind, prev_kind - ); + debug!("actual hash {} did not match expected {}", hash, data.hash()); } } @@ -677,7 +623,7 @@ impl CStore { None => (&source, &crate_root), }; let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate"); - Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?) + Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?) } else { None }; @@ -818,9 +764,7 @@ impl CStore { let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate }; let private_dep = origin.private_dep(); - let result = if let Some(cnum) = - self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind) - { + let result = if let Some(cnum) = self.existing_match(name, hash) { (LoadResult::Previous(cnum), None) } else { info!("falling back to a load"); diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 9fef22f9558dd..c4083a27e72b2 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -218,7 +218,7 @@ use std::ops::Deref; use std::path::{Path, PathBuf}; use std::{cmp, fmt}; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; use rustc_data_structures::svh::Svh; @@ -401,7 +401,7 @@ impl<'a> CrateLocator<'a> { let mut candidates: FxIndexMap< _, - (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>), + (FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>), > = Default::default(); // First, find all possible candidate rlibs and dylibs purely based on @@ -460,10 +460,10 @@ impl<'a> CrateLocator<'a> { // filesystem code should not care, but this is nicer for diagnostics. let path = spf.path.to_path_buf(); match kind { - CrateFlavor::Rlib => rlibs.insert(path, search_path.kind), - CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind), - CrateFlavor::Dylib => dylibs.insert(path, search_path.kind), - CrateFlavor::SDylib => interfaces.insert(path, search_path.kind), + CrateFlavor::Rlib => rlibs.insert(path), + CrateFlavor::Rmeta => rmetas.insert(path), + CrateFlavor::Dylib => dylibs.insert(path), + CrateFlavor::SDylib => interfaces.insert(path), }; } } @@ -524,10 +524,10 @@ impl<'a> CrateLocator<'a> { fn extract_lib( &self, crate_rejections: &mut CrateRejections, - rlibs: FxIndexMap, - rmetas: FxIndexMap, - dylibs: FxIndexMap, - interfaces: FxIndexMap, + rlibs: FxIndexSet, + rmetas: FxIndexSet, + dylibs: FxIndexSet, + interfaces: FxIndexSet, ) -> Result, CrateError> { let mut slot = None; // Order here matters, rmeta should come first. @@ -575,10 +575,10 @@ impl<'a> CrateLocator<'a> { fn extract_one( &self, crate_rejections: &mut CrateRejections, - m: FxIndexMap, + m: FxIndexSet, flavor: CrateFlavor, slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>, - ) -> Result, CrateError> { + ) -> Result, CrateError> { // If we are producing an rlib, and we've already loaded metadata, then // we should not attempt to discover further crate sources (unless we're // locating a proc macro; exact logic is in needs_crate_flavor). This means @@ -594,9 +594,9 @@ impl<'a> CrateLocator<'a> { } } - let mut ret: Option<(PathBuf, PathKind)> = None; + let mut ret: Option = None; let mut err_data: Option> = None; - for (lib, kind) in m { + for lib in m { info!("{} reading metadata from: {}", flavor, lib.display()); if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) { // Empty files will cause get_metadata_section to fail. Rmeta @@ -640,7 +640,7 @@ impl<'a> CrateLocator<'a> { info!("no metadata found: {}", err); // Metadata was loaded from interface file earlier. if let Some((.., CrateFlavor::SDylib)) = slot { - ret = Some((lib, kind)); + ret = Some(lib); continue; } // The file was present and created by the same compiler version, but we @@ -689,7 +689,7 @@ impl<'a> CrateLocator<'a> { // As a result, we favor the sysroot crate here. Note that the // candidates are all canonicalized, so we canonicalize the sysroot // as well. - if let Some((prev, _)) = &ret { + if let Some(prev) = &ret { let sysroot = self.sysroot; let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf()); if prev.starts_with(&sysroot) { @@ -714,7 +714,7 @@ impl<'a> CrateLocator<'a> { } else { *slot = Some((hash, metadata, lib.clone(), flavor)); } - ret = Some((lib, kind)); + ret = Some(lib); } if let Some(candidates) = err_data { @@ -774,10 +774,10 @@ impl<'a> CrateLocator<'a> { // First, filter out all libraries that look suspicious. We only accept // files which actually exist that have the correct naming scheme for // rlibs/dylibs. - let mut rlibs = FxIndexMap::default(); - let mut rmetas = FxIndexMap::default(); - let mut dylibs = FxIndexMap::default(); - let mut sdylib_interfaces = FxIndexMap::default(); + let mut rlibs = FxIndexSet::default(); + let mut rmetas = FxIndexSet::default(); + let mut dylibs = FxIndexSet::default(); + let mut sdylib_interfaces = FxIndexSet::default(); for loc in &self.exact_paths { let loc_canon = loc.canonicalized(); let loc_orig = loc.original(); @@ -798,21 +798,21 @@ impl<'a> CrateLocator<'a> { }; if file.starts_with("lib") { if file.ends_with(".rlib") { - rlibs.insert(loc_canon.clone(), PathKind::ExternFlag); + rlibs.insert(loc_canon.clone()); continue; } if file.ends_with(".rmeta") { - rmetas.insert(loc_canon.clone(), PathKind::ExternFlag); + rmetas.insert(loc_canon.clone()); continue; } if file.ends_with(".rs") { - sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag); + sdylib_interfaces.insert(loc_canon.clone()); } } let dll_prefix = self.target.dll_prefix.as_ref(); let dll_suffix = self.target.dll_suffix.as_ref(); if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) { - dylibs.insert(loc_canon.clone(), PathKind::ExternFlag); + dylibs.insert(loc_canon.clone()); continue; } crate_rejections diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index 30f6256a75efa..378c32d22ae24 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -15,24 +15,22 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::{Span, Symbol}; -use crate::search_paths::PathKind; - // lonely orphan structs and enums looking for a better home /// Where a crate came from on the local filesystem. One of these three options /// must be non-None. #[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct CrateSource { - pub dylib: Option<(PathBuf, PathKind)>, - pub rlib: Option<(PathBuf, PathKind)>, - pub rmeta: Option<(PathBuf, PathKind)>, - pub sdylib_interface: Option<(PathBuf, PathKind)>, + pub dylib: Option, + pub rlib: Option, + pub rmeta: Option, + pub sdylib_interface: Option, } impl CrateSource { #[inline] pub fn paths(&self) -> impl Iterator { - self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0) + self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()) } } diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index 00e12b45bafb1..2ca390b50dd0e 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -71,7 +71,6 @@ pub enum PathKind { Crate, Dependency, Framework, - ExternFlag, All, } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 01b757bae246b..6309952009575 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1558,7 +1558,7 @@ impl Step for RustcLink { run.never() } - /// Same as `std_link`, only for librustc + /// Same as `StdLink`, only for librustc fn run(self, builder: &Builder<'_>) { let build_compiler = self.build_compiler; let sysroot_compiler = self.sysroot_compiler; @@ -2418,13 +2418,35 @@ pub fn add_to_sysroot( t!(fs::create_dir_all(sysroot_dst)); t!(fs::create_dir_all(sysroot_host_dst)); t!(fs::create_dir_all(self_contained_dst)); + + let mut crates = HashSet::new(); for (path, dependency_type) in builder.read_stamp_file(stamp) { + let filename = path.file_name().unwrap().to_str().unwrap(); let dst = match dependency_type { DependencyType::Host => sysroot_host_dst, DependencyType::Target => sysroot_dst, DependencyType::TargetSelfContained => self_contained_dst, }; - builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular); + builder.copy_link(&path, &dst.join(filename), FileType::Regular); + + // Only insert the part before the . to deduplicate different files for the same crate. + // For example foo-1234.dll and foo-1234.dll.lib. + crates.insert(filename.split_once('.').unwrap().0.to_owned()); + } + + // Check that none of the rustc_* crates have multiple versions. Otherwise using them from + // the sysroot would cause ambiguity errors. We do allow rustc_hash however as it is an + // external dependency that we build multiple copies of. It is re-exported by + // rustc_data_structures, so not being able to use extern crate rustc_hash; is not a big + // issue. + let mut seen_crates = HashSet::new(); + for filestem in crates { + if !filestem.contains("rustc_") || filestem.contains("rustc_hash") { + continue; + } + if !seen_crates.insert(filestem.split_once('-').unwrap().0.to_owned()) { + panic!("duplicate rustc crate {filestem}"); + } } } @@ -2511,7 +2533,13 @@ pub fn run_cargo( if filename.starts_with(&host_root_dir) { // Unless it's a proc macro used in the compiler if crate_types.iter().any(|t| t == "proc-macro") { - deps.push((filename.to_path_buf(), DependencyType::Host)); + // Cargo will compile proc-macros that are part of the rustc workspace twice. + // Once as libmacro-hash.so as build dependency and once as libmacro.so as + // output artifact. Only keep the former to avoid ambiguity when trying to use + // the proc macro from the sysroot. + if filename.file_name().unwrap().to_str().unwrap().contains("-") { + deps.push((filename.to_path_buf(), DependencyType::Host)); + } } continue; } diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index bb8ba196983c4..bf037e3e804fd 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -3,8 +3,8 @@ use std::num::NonZero; use std::sync::Mutex; use rustc_abi::{Align, Size}; +use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; use rustc_errors::{Diag, DiagMessage, Level}; -use rustc_hash::FxHashSet; use rustc_span::{DUMMY_SP, Span, SpanData, Symbol}; use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory; @@ -878,6 +878,6 @@ pub struct SpanDedupDiagnostic(Mutex>); impl SpanDedupDiagnostic { pub const fn new() -> Self { - Self(Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher))) + Self(Mutex::new(FxHashSet::with_hasher(FxBuildHasher))) } } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 383a4e2ea4b04..2ceb12a250629 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -6,7 +6,7 @@ use std::{cmp, iter}; use rand::RngCore; use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants}; use rustc_apfloat::Float; -use rustc_hash::FxHashSet; +use rustc_data_structures::fx::{FxBuildHasher, FxHashSet}; use rustc_hir::Safety; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE}; @@ -647,7 +647,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { RejectOpWith::WarningWithoutBacktrace => { // Deduplicate these warnings *by shim* (not by span) static DEDUP: Mutex> = - Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher)); + Mutex::new(FxHashSet::with_hasher(FxBuildHasher)); let mut emitted_warnings = DEDUP.lock().unwrap(); if !emitted_warnings.contains(op_name) { // First time we are seeing this. diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 5ec2e8edd857d..d6d54c5ce056b 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -57,7 +57,6 @@ extern crate rustc_codegen_ssa; extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_errors; -extern crate rustc_hash; extern crate rustc_hir; extern crate rustc_index; extern crate rustc_log; diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/main.rs b/tests/run-make/duplicate-dependency-no-disambiguate/main.rs new file mode 100644 index 0000000000000..eae6b8b4527df --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/main.rs @@ -0,0 +1,10 @@ +#![feature(custom_inner_attributes)] +#![rustfmt::skip] // use_foo must be referenced before foo + +// Load foo-v2 through use-foo +use use_foo as _; + +// Make sure we don't disambiguate this as foo-v2. +use foo as _; + +fn main() {} diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr b/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr new file mode 100644 index 0000000000000..23caa2caaef6e --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/main.stderr @@ -0,0 +1,12 @@ +error[E0464]: multiple candidates for `rlib` dependency `foo` found + --> main.rs:8:5 + | +LL | use foo as _; + | ^^^ + | + = note: candidate #1: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v1.rlib + = note: candidate #2: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v2.rlib + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0464`. diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs b/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs new file mode 100644 index 0000000000000..7dd6f3840dfae --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs @@ -0,0 +1,54 @@ +//@ needs-target-std + +use run_make_support::{Rustc, cwd, diff, regex, rust_lib_name, rustc}; + +fn rustc_with_common_args() -> Rustc { + let mut rustc = rustc(); + rustc.remap_path_prefix(cwd(), "$DIR"); + rustc.edition("2018"); // Don't require `extern crate` + rustc +} + +fn main() { + rustc_with_common_args() + .input("foo-v1.rs") + .crate_type("rlib") + .crate_name("foo") + .extra_filename("-v1") + .metadata("-v1") + .run(); + + rustc_with_common_args() + .input("foo-v2.rs") + .crate_type("rlib") + .crate_name("foo") + .extra_filename("-v2") + .metadata("-v2") + .run(); + + rustc_with_common_args() + .input("use-foo.rs") + .crate_type("rlib") + .extern_("foo", rust_lib_name("foo-v2")) + .run(); + + let stderr = rustc_with_common_args() + .input("main.rs") + .extern_("foo", rust_lib_name("foo-v1")) + .extern_("foo", rust_lib_name("foo-v2")) + .extern_("use_foo", rust_lib_name("use_foo")) + .library_search_path(cwd()) + .ui_testing() + .run_fail() + .stderr_utf8(); + + diff() + .expected_file("main.stderr") + .normalize( + regex::escape(run_make_support::build_root().canonicalize().unwrap().to_str().unwrap()), + "/build-root", + ) + .normalize(r"\\", "/") + .actual_text("(rustc)", &stderr) + .run(); +} diff --git a/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs b/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs new file mode 100644 index 0000000000000..15c1d27f1b953 --- /dev/null +++ b/tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs @@ -0,0 +1 @@ +use foo as _;