Skip to content

Commit 9db224f

Browse files
committed
Auto merge of #105175 - michaelwoerister:add-stable-ord-trait, r=nagisa
Add StableOrd trait as proposed in MCP 533. The `StableOrd` trait can be used to mark types as having a stable sort order across compilation sessions. Collections that sort their items in a stable way can safely implement HashStable by hashing items in sort order. See rust-lang/compiler-team#533 for more information.
2 parents c5351ad + 56aacb2 commit 9db224f

File tree

7 files changed

+95
-35
lines changed

7 files changed

+95
-35
lines changed

compiler/rustc_abi/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ use std::ops::{Add, AddAssign, Mul, RangeInclusive, Sub};
99
use std::str::FromStr;
1010

1111
use bitflags::bitflags;
12+
#[cfg(feature = "nightly")]
13+
use rustc_data_structures::stable_hasher::StableOrd;
1214
use rustc_index::vec::{Idx, IndexVec};
1315
#[cfg(feature = "nightly")]
1416
use rustc_macros::HashStable_Generic;
@@ -403,6 +405,11 @@ pub struct Size {
403405
raw: u64,
404406
}
405407

408+
// Safety: Ord is implement as just comparing numerical values and numerical values
409+
// are not changed by (de-)serialization.
410+
#[cfg(feature = "nightly")]
411+
unsafe impl StableOrd for Size {}
412+
406413
// This is debug-printed a lot in larger structs, don't waste too much space there
407414
impl fmt::Debug for Size {
408415
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

compiler/rustc_data_structures/src/fingerprint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl stable_hasher::StableHasherResult for Fingerprint {
140140
}
141141
}
142142

143-
impl_stable_hash_via_hash!(Fingerprint);
143+
impl_stable_traits_for_trivial_type!(Fingerprint);
144144

145145
impl<E: Encoder> Encodable<E> for Fingerprint {
146146
#[inline]

compiler/rustc_data_structures/src/sorted_map.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::stable_hasher::{HashStable, StableHasher};
1+
use crate::stable_hasher::{HashStable, StableHasher, StableOrd};
22
use std::borrow::Borrow;
33
use std::cmp::Ordering;
44
use std::iter::FromIterator;
@@ -308,7 +308,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for SortedMap<K, V> {
308308
}
309309
}
310310

311-
impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
311+
impl<K: HashStable<CTX> + StableOrd, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
312312
#[inline]
313313
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
314314
self.data.hash_stable(ctx, hasher);

compiler/rustc_data_structures/src/sorted_map/index_map.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,20 @@ where
120120
self.items.hash(hasher)
121121
}
122122
}
123+
123124
impl<I: Idx, K, V, C> HashStable<C> for SortedIndexMultiMap<I, K, V>
124125
where
125126
K: HashStable<C>,
126127
V: HashStable<C>,
127128
{
128129
fn hash_stable(&self, ctx: &mut C, hasher: &mut StableHasher) {
129-
self.items.hash_stable(ctx, hasher)
130+
let SortedIndexMultiMap {
131+
items,
132+
// We can ignore this field because it is not observable from the outside.
133+
idx_sorted_by_item_key: _,
134+
} = self;
135+
136+
items.hash_stable(ctx, hasher)
130137
}
131138
}
132139

compiler/rustc_data_structures/src/stable_hasher.rs

+68-29
Original file line numberDiff line numberDiff line change
@@ -219,42 +219,72 @@ pub trait ToStableHashKey<HCX> {
219219
fn to_stable_hash_key(&self, hcx: &HCX) -> Self::KeyType;
220220
}
221221

222-
/// Implement HashStable by just calling `Hash::hash()`.
222+
/// Trait for marking a type as having a sort order that is
223+
/// stable across compilation session boundaries. More formally:
224+
///
225+
/// ```txt
226+
/// Ord::cmp(a1, b1) == Ord:cmp(a2, b2)
227+
/// where a2 = decode(encode(a1, context1), context2)
228+
/// b2 = decode(encode(b1, context1), context2)
229+
/// ```
230+
///
231+
/// i.e. the result of `Ord::cmp` is not influenced by encoding
232+
/// the values in one session and then decoding them in another
233+
/// session.
234+
///
235+
/// This is trivially true for types where encoding and decoding
236+
/// don't change the bytes of the values that are used during
237+
/// comparison and comparison only depends on these bytes (as
238+
/// opposed to some non-local state). Examples are u32, String,
239+
/// Path, etc.
240+
///
241+
/// But it is not true for:
242+
/// - `*const T` and `*mut T` because the values of these pointers
243+
/// will change between sessions.
244+
/// - `DefIndex`, `CrateNum`, `LocalDefId`, because their concrete
245+
/// values depend on state that might be different between
246+
/// compilation sessions.
247+
pub unsafe trait StableOrd: Ord {}
248+
249+
/// Implement HashStable by just calling `Hash::hash()`. Also implement `StableOrd` for the type since
250+
/// that has the same requirements.
223251
///
224252
/// **WARNING** This is only valid for types that *really* don't need any context for fingerprinting.
225253
/// But it is easy to misuse this macro (see [#96013](https://github.com/rust-lang/rust/issues/96013)
226254
/// for examples). Therefore this macro is not exported and should only be used in the limited cases
227255
/// here in this module.
228256
///
229257
/// Use `#[derive(HashStable_Generic)]` instead.
230-
macro_rules! impl_stable_hash_via_hash {
258+
macro_rules! impl_stable_traits_for_trivial_type {
231259
($t:ty) => {
232260
impl<CTX> $crate::stable_hasher::HashStable<CTX> for $t {
233261
#[inline]
234262
fn hash_stable(&self, _: &mut CTX, hasher: &mut $crate::stable_hasher::StableHasher) {
235263
::std::hash::Hash::hash(self, hasher);
236264
}
237265
}
266+
267+
unsafe impl $crate::stable_hasher::StableOrd for $t {}
238268
};
239269
}
240270

241-
impl_stable_hash_via_hash!(i8);
242-
impl_stable_hash_via_hash!(i16);
243-
impl_stable_hash_via_hash!(i32);
244-
impl_stable_hash_via_hash!(i64);
245-
impl_stable_hash_via_hash!(isize);
271+
impl_stable_traits_for_trivial_type!(i8);
272+
impl_stable_traits_for_trivial_type!(i16);
273+
impl_stable_traits_for_trivial_type!(i32);
274+
impl_stable_traits_for_trivial_type!(i64);
275+
impl_stable_traits_for_trivial_type!(isize);
246276

247-
impl_stable_hash_via_hash!(u8);
248-
impl_stable_hash_via_hash!(u16);
249-
impl_stable_hash_via_hash!(u32);
250-
impl_stable_hash_via_hash!(u64);
251-
impl_stable_hash_via_hash!(usize);
277+
impl_stable_traits_for_trivial_type!(u8);
278+
impl_stable_traits_for_trivial_type!(u16);
279+
impl_stable_traits_for_trivial_type!(u32);
280+
impl_stable_traits_for_trivial_type!(u64);
281+
impl_stable_traits_for_trivial_type!(usize);
252282

253-
impl_stable_hash_via_hash!(u128);
254-
impl_stable_hash_via_hash!(i128);
283+
impl_stable_traits_for_trivial_type!(u128);
284+
impl_stable_traits_for_trivial_type!(i128);
255285

256-
impl_stable_hash_via_hash!(char);
257-
impl_stable_hash_via_hash!(());
286+
impl_stable_traits_for_trivial_type!(char);
287+
impl_stable_traits_for_trivial_type!(());
258288

259289
impl<CTX> HashStable<CTX> for ! {
260290
fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
@@ -444,6 +474,10 @@ impl<CTX> HashStable<CTX> for String {
444474
}
445475
}
446476

477+
// Safety: String comparison only depends on their contents and the
478+
// contents are not changed by (de-)serialization.
479+
unsafe impl StableOrd for String {}
480+
447481
impl<HCX> ToStableHashKey<HCX> for String {
448482
type KeyType = String;
449483
#[inline]
@@ -459,6 +493,9 @@ impl<CTX> HashStable<CTX> for bool {
459493
}
460494
}
461495

496+
// Safety: sort order of bools is not changed by (de-)serialization.
497+
unsafe impl StableOrd for bool {}
498+
462499
impl<T, CTX> HashStable<CTX> for Option<T>
463500
where
464501
T: HashStable<CTX>,
@@ -474,6 +511,9 @@ where
474511
}
475512
}
476513

514+
// Safety: the Option wrapper does not add instability to comparison.
515+
unsafe impl<T: StableOrd> StableOrd for Option<T> {}
516+
477517
impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
478518
where
479519
T1: HashStable<CTX>,
@@ -550,8 +590,8 @@ where
550590
}
551591
}
552592

553-
impl_stable_hash_via_hash!(::std::path::Path);
554-
impl_stable_hash_via_hash!(::std::path::PathBuf);
593+
impl_stable_traits_for_trivial_type!(::std::path::Path);
594+
impl_stable_traits_for_trivial_type!(::std::path::PathBuf);
555595

556596
impl<K, V, R, HCX> HashStable<HCX> for ::std::collections::HashMap<K, V, R>
557597
where
@@ -584,27 +624,26 @@ where
584624

585625
impl<K, V, HCX> HashStable<HCX> for ::std::collections::BTreeMap<K, V>
586626
where
587-
K: ToStableHashKey<HCX>,
627+
K: HashStable<HCX> + StableOrd,
588628
V: HashStable<HCX>,
589629
{
590630
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
591-
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, (key, value)| {
592-
let key = key.to_stable_hash_key(hcx);
593-
key.hash_stable(hcx, hasher);
594-
value.hash_stable(hcx, hasher);
595-
});
631+
self.len().hash_stable(hcx, hasher);
632+
for entry in self.iter() {
633+
entry.hash_stable(hcx, hasher);
634+
}
596635
}
597636
}
598637

599638
impl<K, HCX> HashStable<HCX> for ::std::collections::BTreeSet<K>
600639
where
601-
K: ToStableHashKey<HCX>,
640+
K: HashStable<HCX> + StableOrd,
602641
{
603642
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
604-
stable_hash_reduce(hcx, hasher, self.iter(), self.len(), |hasher, hcx, key| {
605-
let key = key.to_stable_hash_key(hcx);
606-
key.hash_stable(hcx, hasher);
607-
});
643+
self.len().hash_stable(hcx, hasher);
644+
for entry in self.iter() {
645+
entry.hash_stable(hcx, hasher);
646+
}
608647
}
609648
}
610649

compiler/rustc_hir/src/hir_id.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::def_id::{DefId, DefIndex, LocalDefId, CRATE_DEF_ID};
2-
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
2+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd, ToStableHashKey};
33
use rustc_span::{def_id::DefPathHash, HashStableContext};
44
use std::fmt;
55

@@ -146,6 +146,10 @@ impl ItemLocalId {
146146
pub const INVALID: ItemLocalId = ItemLocalId::MAX;
147147
}
148148

149+
// Safety: Ord is implement as just comparing the LocalItemId's numerical
150+
// values and these are not changed by (de-)serialization.
151+
unsafe impl StableOrd for ItemLocalId {}
152+
149153
/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
150154
pub const CRATE_HIR_ID: HirId =
151155
HirId { owner: OwnerId { def_id: CRATE_DEF_ID }, local_id: ItemLocalId::from_u32(0) };

compiler/rustc_session/src/config.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{lint, HashStableContext};
1010

1111
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1212

13-
use rustc_data_structures::stable_hasher::ToStableHashKey;
13+
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
1414
use rustc_target::abi::Align;
1515
use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
1616
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
@@ -288,6 +288,9 @@ pub enum OutputType {
288288
DepInfo,
289289
}
290290

291+
// Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
292+
unsafe impl StableOrd for OutputType {}
293+
291294
impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
292295
type KeyType = Self;
293296

0 commit comments

Comments
 (0)