diff --git a/libs/Patches.md b/libs/Patches.md index 1dabac65..008ca734 100644 --- a/libs/Patches.md +++ b/libs/Patches.md @@ -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) @@ -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) @@ -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>` 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) @@ -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) @@ -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) @@ -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) @@ -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. diff --git a/libs/core/src/array/mod.rs b/libs/core/src/array/mod.rs index cb196ab5..3abea627 100644 --- a/libs/core/src/array/mod.rs +++ b/libs/core/src/array/mod.rs @@ -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(s: &T) -> &[T; 1] { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_array_from_ref_hook(r: &T) -> &[T; 1] { // SAFETY: Converting `&T` to `&[T; 1]` is sound. unsafe { &*(r as *const T).cast::<[T; 1]>() } diff --git a/libs/core/src/cell.rs b/libs/core/src/cell.rs index 4de7ee25..9f552730 100644 --- a/libs/core/src/cell.rs +++ b/libs/core/src/cell.rs @@ -457,6 +457,7 @@ impl Cell { #[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(src: *const T, dst: *const T) -> bool { let src_usize = src.addr(); let dst_usize = dst.addr(); diff --git a/libs/core/src/num/nonzero.rs b/libs/core/src/num/nonzero.rs index b0fe095f..d91fac05 100644 --- a/libs/core/src/num/nonzero.rs +++ b/libs/core/src/num/nonzero.rs @@ -395,6 +395,7 @@ where #[must_use] #[inline] pub const fn new(n: T) -> Option { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_non_zero_new_hook(n: T) -> Option> { // SAFETY: Memory layout optimization guarantees that `Option>` has // the same layout and size as `T`, with `0` representing `None`. diff --git a/libs/core/src/ptr/mod.rs b/libs/core/src/ptr/mod.rs index 57d71e91..0e5e0550 100644 --- a/libs/core/src/ptr/mod.rs +++ b/libs/core/src/ptr/mod.rs @@ -831,6 +831,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_null_hook() -> *const T { from_raw_parts(without_provenance::<()>(0), ()) } @@ -859,6 +860,7 @@ pub const fn null() -> *const T { #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_null_hook() -> *mut T { from_raw_parts_mut(without_provenance_mut::<()>(0), ()) } diff --git a/libs/core/src/slice/mod.rs b/libs/core/src/slice/mod.rs index 2d3e5de5..bd07d3c8 100644 --- a/libs/core/src/slice/mod.rs +++ b/libs/core/src/slice/mod.rs @@ -845,6 +845,7 @@ impl [T] { #[inline] #[must_use] pub const fn as_array(&self) -> Option<&[T; N]> { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_array_from_slice_hook(slice: &[T]) -> Option<&[T; N]> { if slice.len() == N { let ptr = slice.as_ptr().cast_array(); diff --git a/libs/core/src/slice/raw.rs b/libs/core/src/slice/raw.rs index a70de08f..b5c54fe6 100644 --- a/libs/core/src/slice/raw.rs +++ b/libs/core/src/slice/raw.rs @@ -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(s: &T) -> &[T] { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_slice_from_ref_hook(r: &T) -> &[T] { array::from_ref(r) } @@ -212,6 +213,7 @@ pub const fn from_ref(s: &T) -> &[T] { #[rustc_const_stable(feature = "const_slice_from_ref", since = "1.83.0")] #[must_use] pub const fn from_mut(s: &mut T) -> &mut [T] { + #[inline(never)] // Keep the hook around even with optimizations applied const fn crucible_slice_from_mut_hook(r: &mut T) -> &mut [T] { array::from_mut(r) }