Skip to content

Commit

Permalink
Auto merge of rust-lang#126326 - eggyal:ununsafe-StableOrd, r=michael…
Browse files Browse the repository at this point in the history
…woerister

Un-unsafe the `StableOrd` trait

Whilst incorrect implementations of this trait can cause miscompilation, they cannot cause memory unsafety in rustc.

[Discussed on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Policy.20of.20.60unsafe.60.20within.20the.20compiler).

cc [MCP 533](rust-lang/compiler-team#533), rust-lang#105175, `@michaelwoerister`

r? `@Nilstrieb`
  • Loading branch information
bors committed Jun 25, 2024
2 parents d929a42 + 0e73e70 commit c290e9d
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 28 deletions.
8 changes: 5 additions & 3 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -427,11 +427,13 @@ pub struct Size {
raw: u64,
}

// 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 {
impl StableOrd for Size {
const CAN_USE_UNSTABLE_SORT: bool = true;

// `Ord` is implemented as just comparing numerical values and numerical values
// are not changed by (de-)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

// This is debug-printed a lot in larger structs, don't waste too much space there
Expand Down
71 changes: 54 additions & 17 deletions compiler/rustc_data_structures/src/stable_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,21 @@ pub trait ToStableHashKey<HCX> {
/// 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 {
pub trait StableOrd: Ord {
const CAN_USE_UNSTABLE_SORT: bool;

/// Marker to ensure that implementors have carefully considered
/// whether their `Ord` implementation obeys this trait's contract.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: ();
}

unsafe impl<T: StableOrd> StableOrd for &T {
impl<T: StableOrd> StableOrd for &T {
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;

// Ordering of a reference is exactly that of the referent, and since
// the ordering of the referet is stable so must be the ordering of the
// reference.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

/// This is a companion trait to `StableOrd`. Some types like `Symbol` can be
Expand Down Expand Up @@ -290,8 +299,12 @@ macro_rules! impl_stable_traits_for_trivial_type {
}
}

unsafe impl $crate::stable_hasher::StableOrd for $t {
impl $crate::stable_hasher::StableOrd for $t {
const CAN_USE_UNSTABLE_SORT: bool = true;

// Encoding and decoding doesn't change the bytes of trivial types
// and `Ord::cmp` depends only on those bytes.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}
};
}
Expand Down Expand Up @@ -327,8 +340,12 @@ impl<CTX> HashStable<CTX> for Hash128 {
}
}

unsafe impl StableOrd for Hash128 {
impl StableOrd for Hash128 {
const CAN_USE_UNSTABLE_SORT: bool = true;

// Encoding and decoding doesn't change the bytes of `Hash128`
// and `Ord::cmp` depends only on those bytes.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<CTX> HashStable<CTX> for ! {
Expand Down Expand Up @@ -392,8 +409,12 @@ impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2)
}
}

unsafe impl<T1: StableOrd, T2: StableOrd> StableOrd for (T1, T2) {
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;

// Ordering of tuples is a pure function of their elements' ordering, and since
// the ordering of each element is stable so must be the ordering of the tuple.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<T1, T2, T3, CTX> HashStable<CTX> for (T1, T2, T3)
Expand All @@ -410,9 +431,13 @@ where
}
}

unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd> StableOrd for (T1, T2, T3) {
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;

// Ordering of tuples is a pure function of their elements' ordering, and since
// the ordering of each element is stable so must be the ordering of the tuple.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<T1, T2, T3, T4, CTX> HashStable<CTX> for (T1, T2, T3, T4)
Expand All @@ -431,13 +456,15 @@ where
}
}

unsafe impl<T1: StableOrd, T2: StableOrd, T3: StableOrd, T4: StableOrd> StableOrd
for (T1, T2, T3, T4)
{
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;

// Ordering of tuples is a pure function of their elements' ordering, and since
// the ordering of each element is stable so must be the ordering of the tuple.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
Expand Down Expand Up @@ -530,8 +557,12 @@ impl<CTX> HashStable<CTX> for str {
}
}

unsafe impl StableOrd for &str {
impl StableOrd for &str {
const CAN_USE_UNSTABLE_SORT: bool = true;

// Encoding and decoding doesn't change the bytes of string slices
// and `Ord::cmp` depends only on those bytes.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<CTX> HashStable<CTX> for String {
Expand All @@ -541,10 +572,12 @@ 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 {
impl StableOrd for String {
const CAN_USE_UNSTABLE_SORT: bool = true;

// String comparison only depends on their contents and the
// contents are not changed by (de-)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<HCX> ToStableHashKey<HCX> for String {
Expand All @@ -570,9 +603,11 @@ impl<CTX> HashStable<CTX> for bool {
}
}

// Safety: sort order of bools is not changed by (de-)serialization.
unsafe impl StableOrd for bool {
impl StableOrd for bool {
const CAN_USE_UNSTABLE_SORT: bool = true;

// sort order of bools is not changed by (de-)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<T, CTX> HashStable<CTX> for Option<T>
Expand All @@ -590,9 +625,11 @@ where
}
}

// Safety: the Option wrapper does not add instability to comparison.
unsafe impl<T: StableOrd> StableOrd for Option<T> {
impl<T: StableOrd> StableOrd for Option<T> {
const CAN_USE_UNSTABLE_SORT: bool = T::CAN_USE_UNSTABLE_SORT;

// the Option wrapper does not add instability to comparison.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<T1, T2, CTX> HashStable<CTX> for Result<T1, T2>
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_hir/src/hir_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,12 @@ impl ItemLocalId {
pub const INVALID: ItemLocalId = ItemLocalId::MAX;
}

// 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 {
impl StableOrd for ItemLocalId {
const CAN_USE_UNSTABLE_SORT: bool = true;

// `Ord` is implemented as just comparing the ItemLocalId's numerical
// values and these are not changed by (de-)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

/// The `HirId` corresponding to `CRATE_NODE_ID` and `CRATE_DEF_ID`.
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_query_system/src/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,12 @@ impl<HCX> ToStableHashKey<HCX> for WorkProductId {
self.hash
}
}
unsafe impl StableOrd for WorkProductId {
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;

// `WorkProductId` sort order is not affected by (de)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

// Some types are used a lot. Make sure they don't unintentionally get bigger.
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,9 +498,11 @@ pub enum OutputType {
DepInfo,
}

// Safety: Trivial C-Style enums have a stable sort order across compilation sessions.
unsafe impl StableOrd for OutputType {
impl StableOrd for OutputType {
const CAN_USE_UNSTABLE_SORT: bool = true;

// Trivial C-Style enums have a stable sort order across compilation sessions.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_span/src/def_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ impl Default for DefPathHash {
}
}

// Safety: `DefPathHash` sort order is not affected (de)serialization.
unsafe impl StableOrd for DefPathHash {
impl StableOrd for DefPathHash {
const CAN_USE_UNSTABLE_SORT: bool = true;

// `DefPathHash` sort order is not affected by (de)serialization.
const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
}

/// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all
Expand Down

0 comments on commit c290e9d

Please sign in to comment.