Skip to content

Commit c16cd0a

Browse files
committed
[#224] Add crucible support for core::slice::as_chunks
This commit moves the allocate family of functions into core::crucible::alloc so that as_chunks_unchecked can call them.
1 parent 318f8c4 commit c16cd0a

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

libs/Patches.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,13 @@ into the main commit for that patch, and then the *Update* line can be removed.
291291
* We use the Wasm configuration for the internal `guard::enable` function,
292292
which simply leaks everything.
293293

294+
* Avoid unsupported pointer-cast in `std::slice::as_chunks_unchecked` (last applied Feb 26, 2026)
295+
296+
Due to limitations of the current memory model we need to allocate a new
297+
array of arrays and then shallow-copy the original elements of the slice
298+
into those arrays. We note that this is unsound in the face of interior
299+
mutability and it leaks memory.
300+
294301
# Notes
295302

296303
This section contains more detailed notes about why certain patches are written

libs/core/src/crucible/alloc.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#![expect(unused_variables)]
2+
3+
// These functions have been moved temporarily in support
4+
// of core::slice::as_chunks_unchecked. They should be
5+
// returned to crucible::alloc once they are no longer needed.
6+
7+
/// Allocate an array of `len` elements of type `T`. The array begins uninitialized.
8+
pub fn allocate<T>(len: usize) -> *mut T {
9+
unimplemented!("allocate")
10+
}
11+
12+
/// Allocate an array of `len` elements of type `T`. The array initially contains all zeros. This
13+
/// fails if `crux-mir` doesn't know how to zero-initialize `T`.
14+
pub fn allocate_zeroed<T>(len: usize) -> *mut T {
15+
unimplemented!("allocate_zeroed")
16+
}
17+
18+
/// Reallocate the array at `*ptr` to contain `new_len` elements. This reallocation always happens
19+
/// in-place and never fails, so there is no need to return a new pointer.
20+
pub fn reallocate<T>(ptr: *mut T, new_len: usize) {
21+
unimplemented!("reallocate")
22+
}

libs/core/src/crucible/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ pub mod ptr;
88

99
#[unstable(feature = "crucible_intrinsics", issue = "none")]
1010
pub mod concurrency;
11+
12+
#[unstable(feature = "crucible_intrinsics", issue = "none")]
13+
pub mod alloc;

libs/core/src/slice/mod.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#![stable(feature = "rust1", since = "1.0.0")]
88

99
use crate::cmp::Ordering::{self, Equal, Greater, Less};
10-
use crate::intrinsics::{exact_div, unchecked_sub};
10+
use crate::intrinsics::{const_eval_select, exact_div, unchecked_sub};
1111
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
1212
use crate::num::NonZero;
1313
use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive};
@@ -1332,6 +1332,7 @@ impl<T> [T] {
13321332
/// ```
13331333
#[stable(feature = "slice_as_chunks", since = "1.88.0")]
13341334
#[rustc_const_stable(feature = "slice_as_chunks", since = "1.88.0")]
1335+
#[rustc_allow_const_fn_unstable(const_eval_select)]
13351336
#[inline]
13361337
#[must_use]
13371338
#[track_caller]
@@ -1341,11 +1342,31 @@ impl<T> [T] {
13411342
"slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
13421343
(n: usize = N, len: usize = self.len()) => n != 0 && len.is_multiple_of(n),
13431344
);
1344-
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
1345-
let new_len = unsafe { exact_div(self.len(), N) };
1346-
// SAFETY: We cast a slice of `new_len * N` elements into
1347-
// a slice of `new_len` many `N` elements chunks.
1348-
unsafe { from_raw_parts(self.as_ptr().cast(), new_len) }
1345+
1346+
const fn const_case<T, const N: usize>(xs: &[T]) -> &[[T; N]] {
1347+
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
1348+
let new_len = unsafe { exact_div(xs.len(), N) };
1349+
1350+
// SAFETY: We cast a slice of `new_len * N` elements into
1351+
// a slice of `new_len` many `N` elements chunks.
1352+
unsafe { from_raw_parts(xs.as_ptr().cast(), new_len) }
1353+
}
1354+
1355+
// The non-const case needs to be able to call allocate which is not const fn
1356+
fn mut_case<T, const N: usize>(xs: &[T]) -> &[[T; N]] {
1357+
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
1358+
let new_len = unsafe { exact_div(xs.len(), N) };
1359+
1360+
let ptr = crate::crucible::alloc::allocate::<[T; N]>(new_len);
1361+
for i in 0..new_len {
1362+
unsafe {
1363+
ptr.add(i).write(crate::array::from_fn(|j| xs.as_ptr().add(N*i+j).read()));
1364+
}
1365+
}
1366+
unsafe { from_raw_parts(ptr, new_len) }
1367+
}
1368+
1369+
const_eval_select((self,), const_case, mut_case)
13491370
}
13501371

13511372
/// Splits the slice into a slice of `N`-element arrays,

libs/crucible/alloc.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,21 @@ use core::ptr::NonNull;
55

66
/// Allocate an array of `len` elements of type `T`. The array begins uninitialized.
77
pub fn allocate<T>(len: usize) -> *mut T {
8-
unimplemented!("allocate")
8+
core::crucible::alloc::allocate(len)
99
}
1010

1111
/// Allocate an array of `len` elements of type `T`. The array initially contains all zeros. This
1212
/// fails if `crux-mir` doesn't know how to zero-initialize `T`.
1313
pub fn allocate_zeroed<T>(len: usize) -> *mut T {
14-
unimplemented!("allocate_zeroed")
14+
core::crucible::alloc::allocate_zeroed(len)
1515
}
1616

1717
/// Reallocate the array at `*ptr` to contain `new_len` elements. This reallocation always happens
1818
/// in-place and never fails, so there is no need to return a new pointer.
1919
pub fn reallocate<T>(ptr: *mut T, new_len: usize) {
20-
unimplemented!("reallocate")
20+
core::crucible::alloc::reallocate(ptr, new_len)
2121
}
2222

23-
2423
pub struct TypedAllocator<T>(pub PhantomData<T>);
2524

2625
impl<T> TypedAllocator<T> {

0 commit comments

Comments
 (0)