Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make core::slice::from_raw_parts[_mut] const #90377

Merged
merged 3 commits into from
Oct 30, 2021
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
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_discriminant)]
#![cfg_attr(not(bootstrap), feature(const_eval_select))]
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
#![feature(const_fmt_arguments_new)]
Expand Down
56 changes: 42 additions & 14 deletions library/core/src/slice/raw.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
//! Free functions to create `&[T]` and `&mut [T]`.

use crate::array;
use crate::intrinsics::is_aligned_and_not_null;
use crate::mem;
use crate::ptr;

/// Forms a slice from a pointer and a length.
Expand Down Expand Up @@ -85,12 +83,10 @@ use crate::ptr;
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
debug_assert!(
mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering at least half the address space"
);
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
debug_check_data_len(data, len);

// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe { &*ptr::slice_from_raw_parts(data, len) }
}
Expand Down Expand Up @@ -126,16 +122,48 @@ pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
debug_assert!(
mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering at least half the address space"
);
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
debug_check_data_len(data as _, len);

// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}

// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
#[cfg(all(not(bootstrap), debug_assertions))]
#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
const fn debug_check_data_len<T>(data: *const T, len: usize) {
fn rt_check<T>(data: *const T) {
use crate::intrinsics::is_aligned_and_not_null;

assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
}

const fn noop<T>(_: *const T) {}

// SAFETY:
//
// `rt_check` is just a debug assert to hint users that they are causing UB,
// it is not required for safety (the safety must be guatanteed by
// the `from_raw_parts[_mut]` caller).
//
// Since the checks are not required, we ignore them in CTFE as they can't
// be done there (alignment does not make much sense there).
unsafe {
crate::intrinsics::const_eval_select((data,), noop, rt_check);
}

assert!(
crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
"attempt to create slice covering at least half the address space"
);
}

#[cfg(not(all(not(bootstrap), debug_assertions)))]
const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}

/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
Expand Down