Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 57 additions & 9 deletions libs/Patches.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@ between Rust versions, so applying the patches is rarely as straightforward as
running `git apply`.

As a compromise, this document contains high-level descriptions of each type of
patch that we apply, along with rationale for why the patch is necessary. The
intent is that this document can be used in conjunction with `git blame` to
identify all of the code that was changed in each patch.
patch that we apply, along with the date in which it was last applied and the
rationale for why the patch is necessary. The intent is that this document can
be used in conjunction with `git blame` to identify all of the code that was
changed in each patch. If the rationale for a patch is particularly in-depth,
consider splitting it out into a section in the "Notes" section below.

If you need to update the implementation of a patch later, make sure to include
an *Update* line (along with a date) describing what the patch does. That way,
when the next Rust toolchain upgrade is performed, the update can be folded
into the main commit for that patch, and then the *Update* line can be removed.

* Add reference to `core::crucible` module (last applied: November 18, 2025)

Expand Down Expand Up @@ -50,7 +57,10 @@ identify all of the code that was changed in each patch.

* Use `crucible_array_from_slice_hook` in `<[T]>::as_slice` (last applied: November 19, 2025)

The actual implementation uses a pointer cast that Crucible can't handle.
The actual implementation uses a pointer cast that Crucible can't handle. See
also the "Mark hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Avoid `transmute` in `Layout` and `Alignment` (last applied: November 19, 2025)

Expand All @@ -66,8 +76,11 @@ identify all of the code that was changed in each patch.

The new generic `NonZero::new` relies on transmute to convert `u32` to
`Option<NonZero<u32>>` in a const context. Removing this transmute is
difficult due to limited ability to use generics in a const context.
Instead, we wrap it in a hook that we can override in crucible-mir.
difficult due to limited ability to use generics in a const context. Instead,
we wrap it in a hook that we can override in crucible-mir. See also the "Mark
hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Use crucible's allocator in `Box` constructors (last applied: November 17, 2025)

Expand Down Expand Up @@ -147,6 +160,9 @@ identify all of the code that was changed in each patch.
references before performing the swap and panics if there is overlap. The
overlap check relies pointer-to-integer casts that `crucible-mir` does not
currently support. As such, we use a Crucible override for the overlap check.
See also the "Mark hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Use `no_threads` version of `condvar`, `mutex`, and `rwlock` (last applied: November 27, 2025)

Expand Down Expand Up @@ -183,7 +199,10 @@ identify all of the code that was changed in each patch.

* Use `crucible_array_from_ref_hook` in `core::array::from_ref` (last applied: November 25, 2025)

The actual implementation uses a pointer cast that Crucible can't handle.
The actual implementation uses a pointer cast that Crucible can't handle. See
also the "Mark hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Replace `NonNull::cast` with `transmute` in `TypedAllocator` allocation (last applied: July 25, 2025)

Expand All @@ -192,11 +211,17 @@ identify all of the code that was changed in each patch.

* Use `crucible_slice_from_mut_hook` in `core::slice::from_mut` (last applied: November 25, 2025)

The actual implementation uses a pointer cast that Crucible can't handle.
The actual implementation uses a pointer cast that Crucible can't handle. See
also the "Mark hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Use `crucible_slice_from_ref_hook` in `core::slice::from_ref` (last applied: November 25, 2025)

The actual implementation uses a pointer cast that Crucible can't handle.
The actual implementation uses a pointer cast that Crucible can't handle. See
also the "Mark hook functions as `#[inline(never)]`" note below.

*Update* (December 3, 2025): Add an `#[inline(never)]` attribute.

* Replace `{*mut,NonNull}::cast` with `transmute` in `RawVec` initialization (last applied: November 27, 2025)

Expand All @@ -212,3 +237,26 @@ identify all of the code that was changed in each patch.

This feature was using an `AtomicPtr<()>` with a cast from function
pointer to `*mut ()` that we don't support in its initializer.

# Notes

This section contains more detailed notes about why certain patches are written
the way they are. If you plan to reapply a patch that references one of these
notes, please make sure that the spirit of the note is still upheld in the new
patch. Alternatively, if you choose to deviate from the note, make sure to do
so after carefully considering why deviating is the right choice, and consider
updating the note in the process.

## Mark hook functions as `#[inline(never)]`

We want to ensure that custom hook functions (e.g.,
`crucible_array_from_slice_hook`) are always present in generated MIR code,
regardless of whether or not optimizations are applied. In some cases, it may
not suffice to compile the code containing the hook functions without
optimizations (as `mir-json-translate-libs` currently does), as `rustc` can
still inline code that is contained in a different compilation unit. (See
[#153](https://github.com/GaloisInc/mir-json/issues/153) for an example where
this actually happened.)

As a safeguard, we mark all custom hook functions as `#[inline(never)]` to
ensure that they persist when optimizations are applied.
1 change: 1 addition & 0 deletions libs/core/src/array/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ where
#[stable(feature = "array_from_ref", since = "1.53.0")]
#[rustc_const_stable(feature = "const_array_from_ref_shared", since = "1.63.0")]
pub const fn from_ref<T>(s: &T) -> &[T; 1] {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_array_from_ref_hook<T>(r: &T) -> &[T; 1] {
// SAFETY: Converting `&T` to `&[T; 1]` is sound.
unsafe { &*(r as *const T).cast::<[T; 1]>() }
Expand Down
1 change: 1 addition & 0 deletions libs/core/src/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,7 @@ impl<T> Cell<T> {
#[inline]
#[stable(feature = "move_cell", since = "1.17.0")]
pub fn swap(&self, other: &Self) {
#[inline(never)] // Keep the hook around even with optimizations applied
fn crucible_cell_swap_is_nonoverlapping_hook<T>(src: *const T, dst: *const T) -> bool {
let src_usize = src.addr();
let dst_usize = dst.addr();
Expand Down
1 change: 1 addition & 0 deletions libs/core/src/num/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ where
#[must_use]
#[inline]
pub const fn new(n: T) -> Option<Self> {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_non_zero_new_hook<T: ZeroablePrimitive>(n: T) -> Option<NonZero<T>> {
// SAFETY: Memory layout optimization guarantees that `Option<NonZero<T>>` has
// the same layout and size as `T`, with `0` representing `None`.
Expand Down
2 changes: 2 additions & 0 deletions libs/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
#[rustc_diagnostic_item = "ptr_null"]
pub const fn null<T: PointeeSized + Thin>() -> *const T {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_null_hook<T: ?Sized + Thin>() -> *const T {
from_raw_parts(without_provenance::<()>(0), ())
}
Expand Down Expand Up @@ -859,6 +860,7 @@ pub const fn null<T: PointeeSized + Thin>() -> *const T {
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
#[rustc_diagnostic_item = "ptr_null_mut"]
pub const fn null_mut<T: PointeeSized + Thin>() -> *mut T {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_null_hook<T: ?Sized + Thin>() -> *mut T {
from_raw_parts_mut(without_provenance_mut::<()>(0), ())
}
Expand Down
1 change: 1 addition & 0 deletions libs/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,7 @@ impl<T> [T] {
#[inline]
#[must_use]
pub const fn as_array<const N: usize>(&self) -> Option<&[T; N]> {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_array_from_slice_hook<T, const N: usize>(slice: &[T]) -> Option<&[T; N]> {
if slice.len() == N {
let ptr = slice.as_ptr().cast_array();
Expand Down
2 changes: 2 additions & 0 deletions libs/core/src/slice/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a m
#[rustc_diagnostic_item = "slice_from_ref"]
#[must_use]
pub const fn from_ref<T>(s: &T) -> &[T] {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_slice_from_ref_hook<T>(r: &T) -> &[T] {
array::from_ref(r)
}
Expand All @@ -212,6 +213,7 @@ pub const fn from_ref<T>(s: &T) -> &[T] {
#[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")]
#[must_use]
pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
#[inline(never)] // Keep the hook around even with optimizations applied
const fn crucible_slice_from_mut_hook<T>(r: &mut T) -> &mut [T] {
array::from_mut(r)
}
Expand Down