authorbors <bors@rust-lang.org> 2025-12-14 09:16:11 UTC
committerbors <bors@rust-lang.org> 2025-12-14 09:16:11 UTC
log08de25c4ea16d7ecc3ceeb093d4f343a2be30df5
treeb7cc6f5a74171f1024869390f7472f250adb2515
parent3f4dc1e02d759aa3c3807d4efc1f7f6e293536a5
parent7f1828c5926e67cec899d73ebe1af64a610d49c2

Auto merge of #149273 - bjorn3:crate_locator_improvements, r=petrochenkov

Don't leak sysroot crates through dependencies Previously if a dependency of the current crate depended on a sysroot crate, then `extern crate` would in the current crate would pick the first loaded version of said sysroot crate even in case of an ambiguity. This is surprising and brittle. For `-Ldependency=` we already blocked this since rust-lang/rust#110229, but the fix didn't account for sysroot crates. Should fix https://github.com/rust-lang/rust/issues/147966

17 files changed, 185 insertions(+), 127 deletions(-)

compiler/rustc_codegen_ssa/src/back/link.rs+6-12
...@@ -277,7 +277,7 @@ pub fn each_linked_rlib(...@@ -277,7 +277,7 @@ pub fn each_linked_rlib(
277 }277 }
278 let crate_name = info.crate_name[&cnum];278 let crate_name = info.crate_name[&cnum];
279 let used_crate_source = &info.used_crate_source[&cnum];279 let used_crate_source = &info.used_crate_source[&cnum];
280 if let Some((path, _)) = &used_crate_source.rlib {280 if let Some(path) = &used_crate_source.rlib {
281 f(cnum, path);281 f(cnum, path);
282 } else if used_crate_source.rmeta.is_some() {282 } else if used_crate_source.rmeta.is_some() {
283 return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });283 return Err(errors::LinkRlibError::OnlyRmetaFound { crate_name });
...@@ -541,7 +541,7 @@ fn link_staticlib(...@@ -541,7 +541,7 @@ fn link_staticlib(
541 };541 };
542 let crate_name = codegen_results.crate_info.crate_name[&cnum];542 let crate_name = codegen_results.crate_info.crate_name[&cnum];
543 let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum];543 let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum];
544 if let Some((path, _)) = &used_crate_source.dylib {544 if let Some(path) = &used_crate_source.dylib {
545 all_rust_dylibs.push(&**path);545 all_rust_dylibs.push(&**path);
546 } else if used_crate_source.rmeta.is_some() {546 } else if used_crate_source.rmeta.is_some() {
547 sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });547 sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
...@@ -619,7 +619,6 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out...@@ -619,7 +619,6 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
619 .used_crate_source619 .used_crate_source
620 .items()620 .items()
621 .filter_map(|(_, csource)| csource.rlib.as_ref())621 .filter_map(|(_, csource)| csource.rlib.as_ref())
622 .map(|(path, _)| path)
623 .into_sorted_stable_ord();622 .into_sorted_stable_ord();
624623
625 for input_rlib in input_rlibs {624 for input_rlib in input_rlibs {
...@@ -2173,12 +2172,7 @@ fn add_rpath_args(...@@ -2173,12 +2172,7 @@ fn add_rpath_args(
2173 .crate_info2172 .crate_info
2174 .used_crates2173 .used_crates
2175 .iter()2174 .iter()
2176 .filter_map(|cnum| {2175 .filter_map(|cnum| codegen_results.crate_info.used_crate_source[cnum].dylib.as_deref())
2177 codegen_results.crate_info.used_crate_source[cnum]
2178 .dylib
2179 .as_ref()
2180 .map(|(path, _)| &**path)
2181 })
2182 .collect::<Vec<_>>();2176 .collect::<Vec<_>>();
2183 let rpath_config = RPathConfig {2177 let rpath_config = RPathConfig {
2184 libs: &*libs,2178 libs: &*libs,
...@@ -2656,7 +2650,7 @@ fn add_native_libs_from_crate(...@@ -2656,7 +2650,7 @@ fn add_native_libs_from_crate(
26562650
2657 if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() {2651 if link_static && cnum != LOCAL_CRATE && !bundled_libs.is_empty() {
2658 // If rlib contains native libs as archives, unpack them to tmpdir.2652 // If rlib contains native libs as archives, unpack them to tmpdir.
2659 let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0;2653 let rlib = codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap();
2660 archive_builder_builder2654 archive_builder_builder
2661 .extract_bundled_libs(rlib, tmpdir, bundled_libs)2655 .extract_bundled_libs(rlib, tmpdir, bundled_libs)
2662 .unwrap_or_else(|e| sess.dcx().emit_fatal(e));2656 .unwrap_or_else(|e| sess.dcx().emit_fatal(e));
...@@ -2827,7 +2821,7 @@ fn add_upstream_rust_crates(...@@ -2827,7 +2821,7 @@ fn add_upstream_rust_crates(
2827 }2821 }
2828 Linkage::Dynamic => {2822 Linkage::Dynamic => {
2829 let src = &codegen_results.crate_info.used_crate_source[&cnum];2823 let src = &codegen_results.crate_info.used_crate_source[&cnum];
2830 add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0);2824 add_dynamic_crate(cmd, sess, src.dylib.as_ref().unwrap());
2831 }2825 }
2832 }2826 }
28332827
...@@ -2955,7 +2949,7 @@ fn add_static_crate(...@@ -2955,7 +2949,7 @@ fn add_static_crate(
2955 bundled_lib_file_names: &FxIndexSet<Symbol>,2949 bundled_lib_file_names: &FxIndexSet<Symbol>,
2956) {2950) {
2957 let src = &codegen_results.crate_info.used_crate_source[&cnum];2951 let src = &codegen_results.crate_info.used_crate_source[&cnum];
2958 let cratepath = &src.rlib.as_ref().unwrap().0;2952 let cratepath = src.rlib.as_ref().unwrap();
29592953
2960 let mut link_upstream =2954 let mut link_upstream =
2961 |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false);2955 |path: &Path| cmd.link_staticlib_by_path(&rehome_lib_path(sess, path), false);
compiler/rustc_data_structures/src/fx.rs+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1use std::hash::BuildHasherDefault;1use std::hash::BuildHasherDefault;
22
3pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};3pub use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
44
5pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>;5pub type StdEntry<'a, K, V> = std::collections::hash_map::Entry<'a, K, V>;
66
compiler/rustc_interface/src/passes.rs+3-3
...@@ -680,19 +680,19 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P...@@ -680,19 +680,19 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
680680
681 for &cnum in tcx.crates(()) {681 for &cnum in tcx.crates(()) {
682 let source = tcx.used_crate_source(cnum);682 let source = tcx.used_crate_source(cnum);
683 if let Some((path, _)) = &source.dylib {683 if let Some(path) = &source.dylib {
684 files.extend(hash_iter_files(684 files.extend(hash_iter_files(
685 iter::once(escape_dep_filename(&path.display().to_string())),685 iter::once(escape_dep_filename(&path.display().to_string())),
686 checksum_hash_algo,686 checksum_hash_algo,
687 ));687 ));
688 }688 }
689 if let Some((path, _)) = &source.rlib {689 if let Some(path) = &source.rlib {
690 files.extend(hash_iter_files(690 files.extend(hash_iter_files(
691 iter::once(escape_dep_filename(&path.display().to_string())),691 iter::once(escape_dep_filename(&path.display().to_string())),
692 checksum_hash_algo,692 checksum_hash_algo,
693 ));693 ));
694 }694 }
695 if let Some((path, _)) = &source.rmeta {695 if let Some(path) = &source.rmeta {
696 files.extend(hash_iter_files(696 files.extend(hash_iter_files(
697 iter::once(escape_dep_filename(&path.display().to_string())),697 iter::once(escape_dep_filename(&path.display().to_string())),
698 checksum_hash_algo,698 checksum_hash_algo,
compiler/rustc_metadata/src/creader.rs+11-67
...@@ -135,16 +135,16 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {...@@ -135,16 +135,16 @@ impl<'a> std::fmt::Debug for CrateDump<'a> {
135 writeln!(fmt, " priv: {:?}", data.is_private_dep())?;135 writeln!(fmt, " priv: {:?}", data.is_private_dep())?;
136 let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();136 let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source();
137 if let Some(dylib) = dylib {137 if let Some(dylib) = dylib {
138 writeln!(fmt, " dylib: {}", dylib.0.display())?;138 writeln!(fmt, " dylib: {}", dylib.display())?;
139 }139 }
140 if let Some(rlib) = rlib {140 if let Some(rlib) = rlib {
141 writeln!(fmt, " rlib: {}", rlib.0.display())?;141 writeln!(fmt, " rlib: {}", rlib.display())?;
142 }142 }
143 if let Some(rmeta) = rmeta {143 if let Some(rmeta) = rmeta {
144 writeln!(fmt, " rmeta: {}", rmeta.0.display())?;144 writeln!(fmt, " rmeta: {}", rmeta.display())?;
145 }145 }
146 if let Some(sdylib_interface) = sdylib_interface {146 if let Some(sdylib_interface) = sdylib_interface {
147 writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?;147 writeln!(fmt, " sdylib interface: {}", sdylib_interface.display())?;
148 }148 }
149 }149 }
150 Ok(())150 Ok(())
...@@ -515,73 +515,19 @@ impl CStore {...@@ -515,73 +515,19 @@ impl CStore {
515 }515 }
516 }516 }
517517
518 fn existing_match(518 fn existing_match(&self, name: Symbol, hash: Option<Svh>) -> Option<CrateNum> {
519 &self,519 let hash = hash?;
520 externs: &Externs,520
521 name: Symbol,
522 hash: Option<Svh>,
523 kind: PathKind,
524 ) -> Option<CrateNum> {
525 for (cnum, data) in self.iter_crate_data() {521 for (cnum, data) in self.iter_crate_data() {
526 if data.name() != name {522 if data.name() != name {
527 trace!("{} did not match {}", data.name(), name);523 trace!("{} did not match {}", data.name(), name);
528 continue;524 continue;
529 }525 }
530526
531 match hash {527 if hash == data.hash() {
532 Some(hash) if hash == data.hash() => return Some(cnum),
533 Some(hash) => {
534 debug!("actual hash {} did not match expected {}", hash, data.hash());
535 continue;
536 }
537 None => {}
538 }
539
540 // When the hash is None we're dealing with a top-level dependency
541 // in which case we may have a specification on the command line for
542 // this library. Even though an upstream library may have loaded
543 // something of the same name, we have to make sure it was loaded
544 // from the exact same location as well.
545 //
546 // We're also sure to compare *paths*, not actual byte slices. The
547 // `source` stores paths which are normalized which may be different
548 // from the strings on the command line.
549 let source = data.source();
550 if let Some(entry) = externs.get(name.as_str()) {
551 // Only use `--extern crate_name=path` here, not `--extern crate_name`.
552 if let Some(mut files) = entry.files() {
553 if files.any(|l| {
554 let l = l.canonicalized();
555 source.dylib.as_ref().map(|(p, _)| p) == Some(l)
556 || source.rlib.as_ref().map(|(p, _)| p) == Some(l)
557 || source.rmeta.as_ref().map(|(p, _)| p) == Some(l)
558 }) {
559 return Some(cnum);
560 }
561 }
562 continue;
563 }
564
565 // Alright, so we've gotten this far which means that `data` has the
566 // right name, we don't have a hash, and we don't have a --extern
567 // pointing for ourselves. We're still not quite yet done because we
568 // have to make sure that this crate was found in the crate lookup
569 // path (this is a top-level dependency) as we don't want to
570 // implicitly load anything inside the dependency lookup path.
571 let prev_kind = source
572 .dylib
573 .as_ref()
574 .or(source.rlib.as_ref())
575 .or(source.rmeta.as_ref())
576 .expect("No sources for crate")
577 .1;
578 if kind.matches(prev_kind) {
579 return Some(cnum);528 return Some(cnum);
580 } else {529 } else {
581 debug!(530 debug!("actual hash {} did not match expected {}", hash, data.hash());
582 "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}",
583 name, kind, prev_kind
584 );
585 }531 }
586 }532 }
587533
...@@ -678,7 +624,7 @@ impl CStore {...@@ -678,7 +624,7 @@ impl CStore {
678 None => (&source, &crate_root),624 None => (&source, &crate_root),
679 };625 };
680 let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");626 let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate");
681 Some(self.dlsym_proc_macros(tcx.sess, &dlsym_dylib.0, dlsym_root.stable_crate_id())?)627 Some(self.dlsym_proc_macros(tcx.sess, dlsym_dylib, dlsym_root.stable_crate_id())?)
682 } else {628 } else {
683 None629 None
684 };630 };
...@@ -819,9 +765,7 @@ impl CStore {...@@ -819,9 +765,7 @@ impl CStore {
819 let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };765 let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate };
820 let private_dep = origin.private_dep();766 let private_dep = origin.private_dep();
821767
822 let result = if let Some(cnum) =768 let result = if let Some(cnum) = self.existing_match(name, hash) {
823 self.existing_match(&tcx.sess.opts.externs, name, hash, path_kind)
824 {
825 (LoadResult::Previous(cnum), None)769 (LoadResult::Previous(cnum), None)
826 } else {770 } else {
827 info!("falling back to a load");771 info!("falling back to a load");
compiler/rustc_metadata/src/locator.rs+25-25
...@@ -218,7 +218,7 @@ use std::ops::Deref;...@@ -218,7 +218,7 @@ use std::ops::Deref;
218use std::path::{Path, PathBuf};218use std::path::{Path, PathBuf};
219use std::{cmp, fmt};219use std::{cmp, fmt};
220220
221use rustc_data_structures::fx::{FxHashSet, FxIndexMap};221use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
222use rustc_data_structures::memmap::Mmap;222use rustc_data_structures::memmap::Mmap;
223use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};223use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
224use rustc_data_structures::svh::Svh;224use rustc_data_structures::svh::Svh;
...@@ -401,7 +401,7 @@ impl<'a> CrateLocator<'a> {...@@ -401,7 +401,7 @@ impl<'a> CrateLocator<'a> {
401401
402 let mut candidates: FxIndexMap<402 let mut candidates: FxIndexMap<
403 _,403 _,
404 (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>),404 (FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>, FxIndexSet<_>),
405 > = Default::default();405 > = Default::default();
406406
407 // First, find all possible candidate rlibs and dylibs purely based on407 // First, find all possible candidate rlibs and dylibs purely based on
...@@ -460,10 +460,10 @@ impl<'a> CrateLocator<'a> {...@@ -460,10 +460,10 @@ impl<'a> CrateLocator<'a> {
460 // filesystem code should not care, but this is nicer for diagnostics.460 // filesystem code should not care, but this is nicer for diagnostics.
461 let path = spf.path.to_path_buf();461 let path = spf.path.to_path_buf();
462 match kind {462 match kind {
463 CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),463 CrateFlavor::Rlib => rlibs.insert(path),
464 CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),464 CrateFlavor::Rmeta => rmetas.insert(path),
465 CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),465 CrateFlavor::Dylib => dylibs.insert(path),
466 CrateFlavor::SDylib => interfaces.insert(path, search_path.kind),466 CrateFlavor::SDylib => interfaces.insert(path),
467 };467 };
468 }468 }
469 }469 }
...@@ -524,10 +524,10 @@ impl<'a> CrateLocator<'a> {...@@ -524,10 +524,10 @@ impl<'a> CrateLocator<'a> {
524 fn extract_lib(524 fn extract_lib(
525 &self,525 &self,
526 crate_rejections: &mut CrateRejections,526 crate_rejections: &mut CrateRejections,
527 rlibs: FxIndexMap<PathBuf, PathKind>,527 rlibs: FxIndexSet<PathBuf>,
528 rmetas: FxIndexMap<PathBuf, PathKind>,528 rmetas: FxIndexSet<PathBuf>,
529 dylibs: FxIndexMap<PathBuf, PathKind>,529 dylibs: FxIndexSet<PathBuf>,
530 interfaces: FxIndexMap<PathBuf, PathKind>,530 interfaces: FxIndexSet<PathBuf>,
531 ) -> Result<Option<(Svh, Library)>, CrateError> {531 ) -> Result<Option<(Svh, Library)>, CrateError> {
532 let mut slot = None;532 let mut slot = None;
533 // Order here matters, rmeta should come first.533 // Order here matters, rmeta should come first.
...@@ -575,10 +575,10 @@ impl<'a> CrateLocator<'a> {...@@ -575,10 +575,10 @@ impl<'a> CrateLocator<'a> {
575 fn extract_one(575 fn extract_one(
576 &self,576 &self,
577 crate_rejections: &mut CrateRejections,577 crate_rejections: &mut CrateRejections,
578 m: FxIndexMap<PathBuf, PathKind>,578 m: FxIndexSet<PathBuf>,
579 flavor: CrateFlavor,579 flavor: CrateFlavor,
580 slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,580 slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>,
581 ) -> Result<Option<(PathBuf, PathKind)>, CrateError> {581 ) -> Result<Option<PathBuf>, CrateError> {
582 // If we are producing an rlib, and we've already loaded metadata, then582 // If we are producing an rlib, and we've already loaded metadata, then
583 // we should not attempt to discover further crate sources (unless we're583 // we should not attempt to discover further crate sources (unless we're
584 // locating a proc macro; exact logic is in needs_crate_flavor). This means584 // locating a proc macro; exact logic is in needs_crate_flavor). This means
...@@ -594,9 +594,9 @@ impl<'a> CrateLocator<'a> {...@@ -594,9 +594,9 @@ impl<'a> CrateLocator<'a> {
594 }594 }
595 }595 }
596596
597 let mut ret: Option<(PathBuf, PathKind)> = None;597 let mut ret: Option<PathBuf> = None;
598 let mut err_data: Option<Vec<PathBuf>> = None;598 let mut err_data: Option<Vec<PathBuf>> = None;
599 for (lib, kind) in m {599 for lib in m {
600 info!("{} reading metadata from: {}", flavor, lib.display());600 info!("{} reading metadata from: {}", flavor, lib.display());
601 if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) {601 if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) {
602 // Empty files will cause get_metadata_section to fail. Rmeta602 // Empty files will cause get_metadata_section to fail. Rmeta
...@@ -640,7 +640,7 @@ impl<'a> CrateLocator<'a> {...@@ -640,7 +640,7 @@ impl<'a> CrateLocator<'a> {
640 info!("no metadata found: {}", err);640 info!("no metadata found: {}", err);
641 // Metadata was loaded from interface file earlier.641 // Metadata was loaded from interface file earlier.
642 if let Some((.., CrateFlavor::SDylib)) = slot {642 if let Some((.., CrateFlavor::SDylib)) = slot {
643 ret = Some((lib, kind));643 ret = Some(lib);
644 continue;644 continue;
645 }645 }
646 // The file was present and created by the same compiler version, but we646 // The file was present and created by the same compiler version, but we
...@@ -689,7 +689,7 @@ impl<'a> CrateLocator<'a> {...@@ -689,7 +689,7 @@ impl<'a> CrateLocator<'a> {
689 // As a result, we favor the sysroot crate here. Note that the689 // As a result, we favor the sysroot crate here. Note that the
690 // candidates are all canonicalized, so we canonicalize the sysroot690 // candidates are all canonicalized, so we canonicalize the sysroot
691 // as well.691 // as well.
692 if let Some((prev, _)) = &ret {692 if let Some(prev) = &ret {
693 let sysroot = self.sysroot;693 let sysroot = self.sysroot;
694 let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());694 let sysroot = try_canonicalize(sysroot).unwrap_or_else(|_| sysroot.to_path_buf());
695 if prev.starts_with(&sysroot) {695 if prev.starts_with(&sysroot) {
...@@ -714,7 +714,7 @@ impl<'a> CrateLocator<'a> {...@@ -714,7 +714,7 @@ impl<'a> CrateLocator<'a> {
714 } else {714 } else {
715 *slot = Some((hash, metadata, lib.clone(), flavor));715 *slot = Some((hash, metadata, lib.clone(), flavor));
716 }716 }
717 ret = Some((lib, kind));717 ret = Some(lib);
718 }718 }
719719
720 if let Some(candidates) = err_data {720 if let Some(candidates) = err_data {
...@@ -774,10 +774,10 @@ impl<'a> CrateLocator<'a> {...@@ -774,10 +774,10 @@ impl<'a> CrateLocator<'a> {
774 // First, filter out all libraries that look suspicious. We only accept774 // First, filter out all libraries that look suspicious. We only accept
775 // files which actually exist that have the correct naming scheme for775 // files which actually exist that have the correct naming scheme for
776 // rlibs/dylibs.776 // rlibs/dylibs.
777 let mut rlibs = FxIndexMap::default();777 let mut rlibs = FxIndexSet::default();
778 let mut rmetas = FxIndexMap::default();778 let mut rmetas = FxIndexSet::default();
779 let mut dylibs = FxIndexMap::default();779 let mut dylibs = FxIndexSet::default();
780 let mut sdylib_interfaces = FxIndexMap::default();780 let mut sdylib_interfaces = FxIndexSet::default();
781 for loc in &self.exact_paths {781 for loc in &self.exact_paths {
782 let loc_canon = loc.canonicalized();782 let loc_canon = loc.canonicalized();
783 let loc_orig = loc.original();783 let loc_orig = loc.original();
...@@ -798,21 +798,21 @@ impl<'a> CrateLocator<'a> {...@@ -798,21 +798,21 @@ impl<'a> CrateLocator<'a> {
798 };798 };
799 if file.starts_with("lib") {799 if file.starts_with("lib") {
800 if file.ends_with(".rlib") {800 if file.ends_with(".rlib") {
801 rlibs.insert(loc_canon.clone(), PathKind::ExternFlag);801 rlibs.insert(loc_canon.clone());
802 continue;802 continue;
803 }803 }
804 if file.ends_with(".rmeta") {804 if file.ends_with(".rmeta") {
805 rmetas.insert(loc_canon.clone(), PathKind::ExternFlag);805 rmetas.insert(loc_canon.clone());
806 continue;806 continue;
807 }807 }
808 if file.ends_with(".rs") {808 if file.ends_with(".rs") {
809 sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag);809 sdylib_interfaces.insert(loc_canon.clone());
810 }810 }
811 }811 }
812 let dll_prefix = self.target.dll_prefix.as_ref();812 let dll_prefix = self.target.dll_prefix.as_ref();
813 let dll_suffix = self.target.dll_suffix.as_ref();813 let dll_suffix = self.target.dll_suffix.as_ref();
814 if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {814 if file.starts_with(dll_prefix) && file.ends_with(dll_suffix) {
815 dylibs.insert(loc_canon.clone(), PathKind::ExternFlag);815 dylibs.insert(loc_canon.clone());
816 continue;816 continue;
817 }817 }
818 crate_rejections818 crate_rejections
compiler/rustc_session/src/cstore.rs+5-7
...@@ -15,24 +15,22 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};...@@ -15,24 +15,22 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
15use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic};15use rustc_macros::{BlobDecodable, Decodable, Encodable, HashStable_Generic};
16use rustc_span::{Span, Symbol};16use rustc_span::{Span, Symbol};
1717
18use crate::search_paths::PathKind;
19
20// lonely orphan structs and enums looking for a better home18// lonely orphan structs and enums looking for a better home
2119
22/// Where a crate came from on the local filesystem. One of these three options20/// Where a crate came from on the local filesystem. One of these three options
23/// must be non-None.21/// must be non-None.
24#[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)]22#[derive(PartialEq, Clone, Debug, HashStable_Generic, Encodable, Decodable)]
25pub struct CrateSource {23pub struct CrateSource {
26 pub dylib: Option<(PathBuf, PathKind)>,24 pub dylib: Option<PathBuf>,
27 pub rlib: Option<(PathBuf, PathKind)>,25 pub rlib: Option<PathBuf>,
28 pub rmeta: Option<(PathBuf, PathKind)>,26 pub rmeta: Option<PathBuf>,
29 pub sdylib_interface: Option<(PathBuf, PathKind)>,27 pub sdylib_interface: Option<PathBuf>,
30}28}
3129
32impl CrateSource {30impl CrateSource {
33 #[inline]31 #[inline]
34 pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {32 pub fn paths(&self) -> impl Iterator<Item = &PathBuf> {
35 self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).map(|p| &p.0)33 self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter())
36 }34 }
37}35}
3836
compiler/rustc_session/src/search_paths.rs-1
...@@ -71,7 +71,6 @@ pub enum PathKind {...@@ -71,7 +71,6 @@ pub enum PathKind {
71 Crate,71 Crate,
72 Dependency,72 Dependency,
73 Framework,73 Framework,
74 ExternFlag,
75 All,74 All,
76}75}
7776
src/bootstrap/src/core/build_steps/compile.rs+51-6
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
7//! goes along from the output of the previous stage.7//! goes along from the output of the previous stage.
88
9use std::borrow::Cow;9use std::borrow::Cow;
10use std::collections::HashSet;10use std::collections::{HashMap, HashSet};
11use std::ffi::OsStr;11use std::ffi::OsStr;
12use std::io::BufReader;12use std::io::BufReader;
13use std::io::prelude::*;13use std::io::prelude::*;
...@@ -1562,7 +1562,7 @@ impl Step for RustcLink {...@@ -1562,7 +1562,7 @@ impl Step for RustcLink {
1562 run.never()1562 run.never()
1563 }1563 }
15641564
1565 /// Same as `std_link`, only for librustc1565 /// Same as `StdLink`, only for librustc
1566 fn run(self, builder: &Builder<'_>) {1566 fn run(self, builder: &Builder<'_>) {
1567 let build_compiler = self.build_compiler;1567 let build_compiler = self.build_compiler;
1568 let sysroot_compiler = self.sysroot_compiler;1568 let sysroot_compiler = self.sysroot_compiler;
...@@ -2422,13 +2422,52 @@ pub fn add_to_sysroot(...@@ -2422,13 +2422,52 @@ pub fn add_to_sysroot(
2422 t!(fs::create_dir_all(sysroot_dst));2422 t!(fs::create_dir_all(sysroot_dst));
2423 t!(fs::create_dir_all(sysroot_host_dst));2423 t!(fs::create_dir_all(sysroot_host_dst));
2424 t!(fs::create_dir_all(self_contained_dst));2424 t!(fs::create_dir_all(self_contained_dst));
2425
2426 let mut crates = HashMap::new();
2425 for (path, dependency_type) in builder.read_stamp_file(stamp) {2427 for (path, dependency_type) in builder.read_stamp_file(stamp) {
2428 let filename = path.file_name().unwrap().to_str().unwrap();
2426 let dst = match dependency_type {2429 let dst = match dependency_type {
2427 DependencyType::Host => sysroot_host_dst,2430 DependencyType::Host => {
2428 DependencyType::Target => sysroot_dst,2431 if sysroot_dst == sysroot_host_dst {
2432 // Only insert the part before the . to deduplicate different files for the same crate.
2433 // For example foo-1234.dll and foo-1234.dll.lib.
2434 crates.insert(filename.split_once('.').unwrap().0.to_owned(), path.clone());
2435 }
2436
2437 sysroot_host_dst
2438 }
2439 DependencyType::Target => {
2440 // Only insert the part before the . to deduplicate different files for the same crate.
2441 // For example foo-1234.dll and foo-1234.dll.lib.
2442 crates.insert(filename.split_once('.').unwrap().0.to_owned(), path.clone());
2443
2444 sysroot_dst
2445 }
2429 DependencyType::TargetSelfContained => self_contained_dst,2446 DependencyType::TargetSelfContained => self_contained_dst,
2430 };2447 };
2431 builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular);2448 builder.copy_link(&path, &dst.join(filename), FileType::Regular);
2449 }
2450
2451 // Check that none of the rustc_* crates have multiple versions. Otherwise using them from
2452 // the sysroot would cause ambiguity errors. We do allow rustc_hash however as it is an
2453 // external dependency that we build multiple copies of. It is re-exported by
2454 // rustc_data_structures, so not being able to use extern crate rustc_hash; is not a big
2455 // issue.
2456 let mut seen_crates = HashMap::new();
2457 for (filestem, path) in crates {
2458 if !filestem.contains("rustc_") || filestem.contains("rustc_hash") {
2459 continue;
2460 }
2461 if let Some(other_path) =
2462 seen_crates.insert(filestem.split_once('-').unwrap().0.to_owned(), path.clone())
2463 {
2464 panic!(
2465 "duplicate rustc crate {}\n- first copy at {}\n- second copy at {}",
2466 filestem.split_once('-').unwrap().0.to_owned(),
2467 other_path.display(),
2468 path.display(),
2469 );
2470 }
2432 }2471 }
2433}2472}
24342473
...@@ -2515,7 +2554,13 @@ pub fn run_cargo(...@@ -2515,7 +2554,13 @@ pub fn run_cargo(
2515 if filename.starts_with(&host_root_dir) {2554 if filename.starts_with(&host_root_dir) {
2516 // Unless it's a proc macro used in the compiler2555 // Unless it's a proc macro used in the compiler
2517 if crate_types.iter().any(|t| t == "proc-macro") {2556 if crate_types.iter().any(|t| t == "proc-macro") {
2518 deps.push((filename.to_path_buf(), DependencyType::Host));2557 // Cargo will compile proc-macros that are part of the rustc workspace twice.
2558 // Once as libmacro-hash.so as build dependency and once as libmacro.so as
2559 // output artifact. Only keep the former to avoid ambiguity when trying to use
2560 // the proc macro from the sysroot.
2561 if filename.file_name().unwrap().to_str().unwrap().contains("-") {
2562 deps.push((filename.to_path_buf(), DependencyType::Host));
2563 }
2519 }2564 }
2520 continue;2565 continue;
2521 }2566 }
src/tools/miri/src/diagnostics.rs+2-2
...@@ -3,8 +3,8 @@ use std::num::NonZero;...@@ -3,8 +3,8 @@ use std::num::NonZero;
3use std::sync::Mutex;3use std::sync::Mutex;
44
5use rustc_abi::{Align, Size};5use rustc_abi::{Align, Size};
6use rustc_data_structures::fx::{FxBuildHasher, FxHashSet};
6use rustc_errors::{Diag, DiagMessage, Level};7use rustc_errors::{Diag, DiagMessage, Level};
7use rustc_hash::FxHashSet;
8use rustc_span::{DUMMY_SP, Span, SpanData, Symbol};8use rustc_span::{DUMMY_SP, Span, SpanData, Symbol};
99
10use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;10use crate::borrow_tracker::stacked_borrows::diagnostics::TagHistory;
...@@ -899,6 +899,6 @@ pub struct SpanDedupDiagnostic(Mutex<FxHashSet<Span>>);...@@ -899,6 +899,6 @@ pub struct SpanDedupDiagnostic(Mutex<FxHashSet<Span>>);
899899
900impl SpanDedupDiagnostic {900impl SpanDedupDiagnostic {
901 pub const fn new() -> Self {901 pub const fn new() -> Self {
902 Self(Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher)))902 Self(Mutex::new(FxHashSet::with_hasher(FxBuildHasher)))
903 }903 }
904}904}
src/tools/miri/src/helpers.rs+2-2
...@@ -6,7 +6,7 @@ use std::{cmp, iter};...@@ -6,7 +6,7 @@ use std::{cmp, iter};
6use rand::RngCore;6use rand::RngCore;
7use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};7use rustc_abi::{Align, ExternAbi, FieldIdx, FieldsShape, Size, Variants};
8use rustc_apfloat::Float;8use rustc_apfloat::Float;
9use rustc_hash::FxHashSet;9use rustc_data_structures::fx::{FxBuildHasher, FxHashSet};
10use rustc_hir::Safety;10use rustc_hir::Safety;
11use rustc_hir::def::{DefKind, Namespace};11use rustc_hir::def::{DefKind, Namespace};
12use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE};12use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE};
...@@ -663,7 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {...@@ -663,7 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
663 RejectOpWith::WarningWithoutBacktrace => {663 RejectOpWith::WarningWithoutBacktrace => {
664 // Deduplicate these warnings *by shim* (not by span)664 // Deduplicate these warnings *by shim* (not by span)
665 static DEDUP: Mutex<FxHashSet<String>> =665 static DEDUP: Mutex<FxHashSet<String>> =
666 Mutex::new(FxHashSet::with_hasher(rustc_hash::FxBuildHasher));666 Mutex::new(FxHashSet::with_hasher(FxBuildHasher));
667 let mut emitted_warnings = DEDUP.lock().unwrap();667 let mut emitted_warnings = DEDUP.lock().unwrap();
668 if !emitted_warnings.contains(op_name) {668 if !emitted_warnings.contains(op_name) {
669 // First time we are seeing this.669 // First time we are seeing this.
src/tools/miri/src/lib.rs-1
...@@ -58,7 +58,6 @@ extern crate rustc_codegen_ssa;...@@ -58,7 +58,6 @@ extern crate rustc_codegen_ssa;
58extern crate rustc_const_eval;58extern crate rustc_const_eval;
59extern crate rustc_data_structures;59extern crate rustc_data_structures;
60extern crate rustc_errors;60extern crate rustc_errors;
61extern crate rustc_hash;
62extern crate rustc_hir;61extern crate rustc_hir;
63extern crate rustc_index;62extern crate rustc_index;
64extern crate rustc_log;63extern crate rustc_log;
tests/run-make/duplicate-dependency-no-disambiguate/foo-v1.rs created+1
...@@ -0,0 +1 @@
1pub struct Foo;
tests/run-make/duplicate-dependency-no-disambiguate/foo-v2.rs created+1
...@@ -0,0 +1 @@
1pub struct Foo;
tests/run-make/duplicate-dependency-no-disambiguate/main.rs created+10
...@@ -0,0 +1,10 @@
1#![feature(custom_inner_attributes)]
2#![rustfmt::skip] // use_foo must be referenced before foo
3
4// Load foo-v2 through use-foo
5use use_foo as _;
6
7// Make sure we don't disambiguate this as foo-v2.
8use foo as _;
9
10fn main() {}
tests/run-make/duplicate-dependency-no-disambiguate/main.stderr created+12
...@@ -0,0 +1,12 @@
1error[E0464]: multiple candidates for `rlib` dependency `foo` found
2 --> main.rs:8:5
3 |
4LL | use foo as _;
5 | ^^^
6 |
7 = note: candidate #1: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v1.rlib
8 = note: candidate #2: /build-root/test/run-make/duplicate-dependency-no-disambiguate/rmake_out/libfoo-v2.rlib
9
10error: aborting due to 1 previous error
11
12For more information about this error, try `rustc --explain E0464`.
tests/run-make/duplicate-dependency-no-disambiguate/rmake.rs created+54
...@@ -0,0 +1,54 @@
1//@ needs-target-std
2
3use run_make_support::{Rustc, cwd, diff, regex, rust_lib_name, rustc};
4
5fn rustc_with_common_args() -> Rustc {
6 let mut rustc = rustc();
7 rustc.remap_path_prefix(cwd(), "$DIR");
8 rustc.edition("2018"); // Don't require `extern crate`
9 rustc
10}
11
12fn main() {
13 rustc_with_common_args()
14 .input("foo-v1.rs")
15 .crate_type("rlib")
16 .crate_name("foo")
17 .extra_filename("-v1")
18 .metadata("-v1")
19 .run();
20
21 rustc_with_common_args()
22 .input("foo-v2.rs")
23 .crate_type("rlib")
24 .crate_name("foo")
25 .extra_filename("-v2")
26 .metadata("-v2")
27 .run();
28
29 rustc_with_common_args()
30 .input("use-foo.rs")
31 .crate_type("rlib")
32 .extern_("foo", rust_lib_name("foo-v2"))
33 .run();
34
35 let stderr = rustc_with_common_args()
36 .input("main.rs")
37 .extern_("foo", rust_lib_name("foo-v1"))
38 .extern_("foo", rust_lib_name("foo-v2"))
39 .extern_("use_foo", rust_lib_name("use_foo"))
40 .library_search_path(cwd())
41 .ui_testing()
42 .run_fail()
43 .stderr_utf8();
44
45 diff()
46 .expected_file("main.stderr")
47 .normalize(
48 regex::escape(run_make_support::build_root().canonicalize().unwrap().to_str().unwrap()),
49 "/build-root",
50 )
51 .normalize(r"\\", "/")
52 .actual_text("(rustc)", &stderr)
53 .run();
54}
tests/run-make/duplicate-dependency-no-disambiguate/use-foo.rs created+1
...@@ -0,0 +1 @@
1use foo as _;