about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_abi/src/lib.rs4
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs45
-rw-r--r--compiler/rustc_data_structures/src/unord.rs8
-rw-r--r--compiler/rustc_hir/src/hir_id.rs4
-rw-r--r--compiler/rustc_incremental/src/assert_module_sources.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs8
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs15
-rw-r--r--compiler/rustc_incremental/src/persist/fs/tests.rs13
-rw-r--r--compiler/rustc_incremental/src/persist/work_product.rs7
-rw-r--r--compiler/rustc_interface/src/queries.rs11
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs6
-rw-r--r--compiler/rustc_session/src/config.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs2
13 files changed, 81 insertions, 48 deletions
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 2ee63c286ba..e1b9987f578 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -414,7 +414,9 @@ pub struct Size {
 // Safety: Ord is implement as just comparing numerical values and numerical values
 // are not changed by (de-)serialization.
 #[cfg(feature = "nightly")]
-unsafe impl StableOrd for Size {}
+unsafe impl StableOrd for Size {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 // This is debug-printed a lot in larger structs, don't waste too much space there
 impl fmt::Debug for Size {
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index a895e28c822..0c1fb7518fa 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -233,7 +233,17 @@ pub trait ToStableHashKey<HCX> {
 ///  - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete
 ///    values depend on state that might be different between
 ///    compilation sessions.
-pub unsafe trait StableOrd: Ord {}
+///
+/// The associated constant `CAN_USE_UNSTABLE_SORT` denotes whether
+/// unstable sorting can be used for this type. Set to true if and
+/// only if `a == b` implies `a` and `b` are fully indistinguishable.
+pub unsafe trait StableOrd: Ord {
+    const CAN_USE_UNSTABLE_SORT: bool;
+}
+
+unsafe impl<T: StableOrd> StableOrd for &T {
+    const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
+}
 
 /// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
 /// that has the same requirements.
@@ -253,7 +263,9 @@ macro_rules! impl_stable_traits_for_trivial_type {
             }
         }
 
-        unsafe impl $crate::stable_hasher::StableOrd for $t {}
+        unsafe impl $crate::stable_hasher::StableOrd for $t {
+            const CAN_USE_UNSTABLE_SORT: bool = true;
+        }
     };
 }
 
@@ -339,7 +351,9 @@ impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2)
     }
 }
 
-unsafe impl<T1: StableOrd, T2: StableOrd> StableOrd for (T1, T2) {}
+unsafe impl<T1: StableOrd, T2: StableOrd> StableOrd for (T1, T2) {
+    const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT;
+}
 
 impl<T1, T2, T3, CTX> HashStable<CTX> for (T1, T2, T3)
 where
@@ -355,7 +369,10 @@ where
     }
 }
 
-unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd> StableOrd for (T1, T2, T3) {}
+unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd> StableOrd for (T1, T2, T3) {
+    const CAN_USE_UNSTABLE_SORT: bool =
+        T1::CAN_USE_UNSTABLE_SORT && T2::CAN_USE_UNSTABLE_SORT && T3::CAN_USE_UNSTABLE_SORT;
+}
 
 impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
 where
@@ -376,6 +393,10 @@ where
 unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd, T4: StableOrd> StableOrd
     for (T1, T2, T3, T4)
 {
+    const CAN_USE_UNSTABLE_SORT: bool = T1::CAN_USE_UNSTABLE_SORT
+        && T2::CAN_USE_UNSTABLE_SORT
+        && T3::CAN_USE_UNSTABLE_SORT
+        && T4::CAN_USE_UNSTABLE_SORT;
 }
 
 impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
@@ -468,7 +489,9 @@ impl<CTX> HashStable<CTX> for str {
     }
 }
 
-unsafe impl StableOrd for &str {}
+unsafe impl StableOrd for &str {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 impl<CTX> HashStable<CTX> for String {
     #[inline]
@@ -479,7 +502,9 @@ impl<CTX> HashStable<CTX> for String {
 
 // Safety: String comparison only depends on their contents and the
 // contents are not changed by (de-)serialization.
-unsafe impl StableOrd for String {}
+unsafe impl StableOrd for String {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 impl<HCX> ToStableHashKey<HCX> for String {
     type KeyType = String;
@@ -505,7 +530,9 @@ impl<CTX> HashStable<CTX> for bool {
 }
 
 // Safety: sort order of bools is not changed by (de-)serialization.
-unsafe impl StableOrd for bool {}
+unsafe impl StableOrd for bool {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 impl<T, CTX> HashStable<CTX> for Option<T>
 where
@@ -523,7 +550,9 @@ where
 }
 
 // Safety: the Option wrapper does not add instability to comparison.
-unsafe impl<T: StableOrd> StableOrd for Option<T> {}
+unsafe impl<T: StableOrd> StableOrd for Option<T> {
+    const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;
+}
 
 impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
 where
diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs
index 6c8d5414631..e18c7b415f6 100644
--- a/compiler/rustc_data_structures/src/unord.rs
+++ b/compiler/rustc_data_structures/src/unord.rs
@@ -140,12 +140,12 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
     }
 
     #[inline]
-    pub fn into_sorted_stable_ord(self, use_stable_sort: bool) -> Vec<T>
+    pub fn into_sorted_stable_ord(self) -> Vec<T>
     where
         T: Ord + StableOrd,
     {
         let mut items: Vec<T> = self.0.collect();
-        if use_stable_sort {
+        if !T::CAN_USE_UNSTABLE_SORT {
             items.sort();
         } else {
             items.sort_unstable()
@@ -161,6 +161,10 @@ impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
         items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
         items
     }
+
+    pub fn collect<C: From<UnordItems<T, I>>>(self) -> C {
+        self.into()
+    }
 }
 
 /// This is a set collection type that tries very hard to not expose
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index d549f52f873..34c61577936 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -166,7 +166,9 @@ impl ItemLocalId {
 
 // Safety: Ord is implement as just comparing the ItemLocalId's numerical
 // values and these are not changed by (de-)serialization.
-unsafe impl StableOrd for ItemLocalId {}
+unsafe impl StableOrd for ItemLocalId {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 /// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
 pub const CRATE_HIR_ID: HirId =
diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs
index 3d9b1c2e741..0111a6d302d 100644
--- a/compiler/rustc_incremental/src/assert_module_sources.rs
+++ b/compiler/rustc_incremental/src/assert_module_sources.rs
@@ -119,7 +119,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
 
         if !self.available_cgus.contains(&cgu_name) {
             let cgu_names: Vec<&str> =
-                self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord(true);
+                self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
             self.tcx.sess.emit_err(errors::NoModuleNamed {
                 span: attr.span,
                 user_path,
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 786a0e0d3b2..cbe77e7b16d 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -198,7 +198,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         let (name, mut auto) = self.auto_labels(item_id, attr);
         let except = self.except(attr);
         let loaded_from_disk = self.loaded_from_disk(attr);
-        for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord(false) {
+        for e in except.items().map(|x| x.as_str()).into_sorted_stable_ord() {
             if !auto.remove(e) {
                 self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
             }
@@ -377,16 +377,16 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                 continue;
             };
             self.checked_attrs.insert(attr.id);
-            for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord(false) {
+            for label in assertion.clean.items().map(|x| x.as_str()).into_sorted_stable_ord() {
                 let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_clean(item_span, dep_node);
             }
-            for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord(false) {
+            for label in assertion.dirty.items().map(|x| x.as_str()).into_sorted_stable_ord() {
                 let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_dirty(item_span, dep_node);
             }
             for label in
-                assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord(false)
+                assertion.loaded_from_disk.items().map(|x| x.as_str()).into_sorted_stable_ord()
             {
                 let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_loaded_from_disk(item_span, dep_node);
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 550772a6881..243057b99bc 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -676,11 +676,8 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
 
     // Delete all lock files, that don't have an associated directory. They must
     // be some kind of leftover
-    let lock_file_to_session_dir_iter = lock_file_to_session_dir
-        .items()
-        .map(|(file, dir)| (file.as_str(), dir.as_ref().map(|y| y.as_str())));
     for (lock_file_name, directory_name) in
-        lock_file_to_session_dir_iter.into_sorted_stable_ord(false)
+        lock_file_to_session_dir.items().into_sorted_stable_ord()
     {
         if directory_name.is_none() {
             let Ok(timestamp) = extract_timestamp_from_session_dir(lock_file_name) else {
@@ -712,10 +709,10 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
     }
 
     // Filter out `None` directories
-    let lock_file_to_session_dir: UnordMap<String, String> =
-        UnordMap::from(lock_file_to_session_dir.into_items().filter_map(
-            |(lock_file_name, directory_name)| directory_name.map(|n| (lock_file_name, n)),
-        ));
+    let lock_file_to_session_dir: UnordMap<String, String> = lock_file_to_session_dir
+        .into_items()
+        .filter_map(|(lock_file_name, directory_name)| directory_name.map(|n| (lock_file_name, n)))
+        .into();
 
     // Delete all session directories that don't have a lock file.
     for directory_name in session_directories {
@@ -821,7 +818,7 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
             }
             None
         });
-    let deletion_candidates = UnordMap::from(deletion_candidates);
+    let deletion_candidates = deletion_candidates.into();
 
     // Delete all but the most recent of the candidates
     all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| {
diff --git a/compiler/rustc_incremental/src/persist/fs/tests.rs b/compiler/rustc_incremental/src/persist/fs/tests.rs
index 4c1cb5725dc..644b8187621 100644
--- a/compiler/rustc_incremental/src/persist/fs/tests.rs
+++ b/compiler/rustc_incremental/src/persist/fs/tests.rs
@@ -2,23 +2,16 @@ use super::*;
 
 #[test]
 fn test_all_except_most_recent() {
-    let computed: UnordMap<_, Option<flock::Lock>> = UnordMap::from_iter([
+    let input: UnordMap<_, Option<flock::Lock>> = UnordMap::from_iter([
         ((UNIX_EPOCH + Duration::new(4, 0), PathBuf::from("4")), None),
         ((UNIX_EPOCH + Duration::new(1, 0), PathBuf::from("1")), None),
         ((UNIX_EPOCH + Duration::new(5, 0), PathBuf::from("5")), None),
         ((UNIX_EPOCH + Duration::new(3, 0), PathBuf::from("3")), None),
         ((UNIX_EPOCH + Duration::new(2, 0), PathBuf::from("2")), None),
     ]);
-    let mut paths = UnordSet::default();
-    paths.extend_unord(all_except_most_recent(computed).into_items().map(|(path, _)| path));
     assert_eq!(
-        UnordSet::from(paths),
-        UnordSet::from_iter([
-            PathBuf::from("1"),
-            PathBuf::from("2"),
-            PathBuf::from("3"),
-            PathBuf::from("4")
-        ])
+        all_except_most_recent(input).into_items().map(|(path, _)| path).into_sorted_stable_ord(),
+        vec![PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4")]
     );
 
     assert!(all_except_most_recent(UnordMap::default()).is_empty());
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index ae604b2ca0b..bce5ca1e16b 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -46,12 +46,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
 
 /// Removes files for a given work product.
 pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
-    for path in work_product
-        .saved_files
-        .items()
-        .map(|(_, path)| path.as_str())
-        .into_sorted_stable_ord(false)
-    {
+    for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() {
         let path = in_incr_comp_dir_sess(sess, path);
         if let Err(err) = std_fs::remove_file(&path) {
             sess.emit_warning(errors::DeleteWorkProduct { path: &path, err });
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 6975fbd917a..455a8129656 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -194,10 +194,15 @@ impl<'tcx> Queries<'tcx> {
             let future_opt = self.dep_graph_future()?.steal();
             let dep_graph = future_opt
                 .and_then(|future| {
-                    let (prev_graph, prev_work_products) =
+                    let (prev_graph, mut prev_work_products) =
                         sess.time("blocked_on_dep_graph_loading", || future.open().open(sess));
-                    let prev_work_products =
-                        FxIndexMap::from_iter(prev_work_products.into_sorted(&(), false));
+                    // Convert from UnordMap to FxIndexMap by sorting
+                    let prev_work_product_ids =
+                        prev_work_products.items().map(|x| *x.0).into_sorted_stable_ord();
+                    let prev_work_products = prev_work_product_ids
+                        .into_iter()
+                        .map(|x| (x, prev_work_products.remove(&x).unwrap()))
+                        .collect::<FxIndexMap<_, _>>();
                     rustc_incremental::build_dep_graph(sess, prev_graph, prev_work_products)
                 })
                 .unwrap_or_else(DepGraph::new_disabled);
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index e0089f28615..39a4cb1b179 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -46,7 +46,7 @@ use super::{DepContext, DepKind, FingerprintStyle};
 use crate::ich::StableHashingContext;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
 use rustc_hir::definitions::DefPathHash;
 use std::fmt;
 use std::hash::Hash;
@@ -254,3 +254,7 @@ impl<HCX> ToStableHashKey<HCX> for WorkProductId {
         self.hash
     }
 }
+unsafe impl StableOrd for WorkProductId {
+    // Fingerprint can use unstable (just a tuple of `u64`s), so WorkProductId can as well
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 0ce83e79097..84d9f75532b 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -311,7 +311,9 @@ pub enum OutputType {
 }
 
 // Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
-unsafe impl StableOrd for OutputType {}
+unsafe impl StableOrd for OutputType {
+    const CAN_USE_UNSTABLE_SORT: bool = true;
+}
 
 impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
     type KeyType = Self;
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index b6e4cd22789..2a3d86988bb 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -160,7 +160,7 @@ impl LateLintPass<'_> for WildcardImports {
                     )
                 };
 
-                let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(false);
+                let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord();
                 let imports_string = if imports.len() == 1 {
                     imports.pop().unwrap()
                 } else if braced_glob {