Skip to content

Commit

Permalink
Auto merge of #97419 - WaffleLapkin:const_from_ptr_range, r=oli-obk
Browse files Browse the repository at this point in the history
Make `from{,_mut}_ptr_range` const

This PR makes the following APIs `const`:
```rust
// core::slice

pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T];
pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T];
```

Tracking issue: #89792.
Feature for `from_ptr_range` as a `const fn`: `slice_from_ptr_range_const`.
Feature for `from_mut_ptr_range` as a `const fn`: `slice_from_mut_ptr_range_const`.

r? `@oli-obk`
  • Loading branch information
bors committed May 31, 2022
2 parents 16a0d03 + 3a2bb78 commit 0a43923
Show file tree
Hide file tree
Showing 7 changed files with 772 additions and 2 deletions.
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
#![feature(ptr_sub_ptr)]
#![feature(receiver_trait)]
#![feature(set_ptr_value)]
#![feature(slice_from_ptr_range)]
#![feature(slice_group_by)]
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
Expand Down
2 changes: 2 additions & 0 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ pub use core::slice::EscapeAscii;
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
pub use core::slice::{from_mut, from_ref};
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
pub use core::slice::{from_mut_ptr_range, from_ptr_range};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
6 changes: 4 additions & 2 deletions library/core/src/slice/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
///
/// [valid]: ptr#safety
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
#[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")]
pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
// SAFETY: the caller must uphold the safety contract for `from_ptr_range`.
unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) }
}
Expand Down Expand Up @@ -263,7 +264,8 @@ pub unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] {
///
/// [valid]: ptr#safety
#[unstable(feature = "slice_from_ptr_range", issue = "89792")]
pub unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
#[rustc_const_unstable(feature = "slice_from_mut_ptr_range_const", issue = "89792")]
pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] {
// SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`.
unsafe { from_raw_parts_mut(range.start, range.end.sub_ptr(range.start)) }
}
106 changes: 106 additions & 0 deletions src/test/ui/const-ptr/allowed_slices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// run-pass
#![feature(
const_slice_from_raw_parts,
slice_from_ptr_range,
const_slice_from_ptr_range,
pointer_byte_offsets,
const_pointer_byte_offsets
)]
use std::{
mem::MaybeUninit,
ptr,
slice::{from_ptr_range, from_raw_parts},
};

// Dangling is ok, as long as it's either for ZST reads or for no reads
pub static S0: &[u32] = unsafe { from_raw_parts(dangling(), 0) };
pub static S1: &[()] = unsafe { from_raw_parts(dangling(), 3) };

// References are always valid of reads of a single element (basically `slice::from_ref`)
pub static S2: &[u32] = unsafe { from_raw_parts(&D0, 1) };
pub static S3: &[MaybeUninit<&u32>] = unsafe { from_raw_parts(&D1, 1) };

// Reinterpreting data is fine, as long as layouts match
pub static S4: &[u8] = unsafe { from_raw_parts((&D0) as *const _ as _, 3) };
// This is only valid because D1 has uninitialized bytes, if it was an initialized pointer,
// that would reinterpret pointers as integers which is UB in CTFE.
pub static S5: &[MaybeUninit<u8>] = unsafe { from_raw_parts((&D1) as *const _ as _, 2) };
// Even though u32 and [bool; 4] have different layouts, D0 has a value that
// is valid as [bool; 4], so this is not UB (it's basically a transmute)
pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) };

// Structs are considered single allocated objects,
// as long as you don't reinterpret padding as initialized
// data everything is ok.
pub static S7: &[u16] = unsafe {
let ptr = (&D2 as *const Struct as *const u16).byte_add(4);

from_raw_parts(ptr, 3)
};
pub static S8: &[MaybeUninit<u16>] = unsafe {
let ptr = &D2 as *const Struct as *const MaybeUninit<u16>;

from_raw_parts(ptr, 6)
};

pub static R0: &[u32] = unsafe { from_ptr_range(dangling()..dangling()) };
// from_ptr_range panics on zst
//pub static R1: &[()] = unsafe { from_ptr_range(dangling(), dangling().byte_add(3)) };
pub static R2: &[u32] = unsafe {
let ptr = &D0 as *const u32;
from_ptr_range(ptr..ptr.add(1))
};
pub static R3: &[MaybeUninit<&u32>] = unsafe {
let ptr = &D1 as *const MaybeUninit<&u32>;
from_ptr_range(ptr..ptr.add(1))
};
pub static R4: &[u8] = unsafe {
let ptr = &D0 as *const u32 as *const u8;
from_ptr_range(ptr..ptr.add(3))
};
pub static R5: &[MaybeUninit<u8>] = unsafe {
let ptr = &D1 as *const MaybeUninit<&u32> as *const MaybeUninit<u8>;
from_ptr_range(ptr..ptr.add(2))
};
pub static R6: &[bool] = unsafe {
let ptr = &D0 as *const u32 as *const bool;
from_ptr_range(ptr..ptr.add(4))
};
pub static R7: &[u16] = unsafe {
let d2 = &D2;
let l = &d2.b as *const u32 as *const u16;
let r = &d2.d as *const u8 as *const u16;

from_ptr_range(l..r)
};
pub static R8: &[MaybeUninit<u16>] = unsafe {
let d2 = &D2;
let l = d2 as *const Struct as *const MaybeUninit<u16>;
let r = &d2.d as *const u8 as *const MaybeUninit<u16>;

from_ptr_range(l..r)
};

// Using valid slice is always valid
pub static R9: &[u32] = unsafe { from_ptr_range(R0.as_ptr_range()) };
pub static R10: &[u32] = unsafe { from_ptr_range(R2.as_ptr_range()) };

const D0: u32 = (1 << 16) | 1;
const D1: MaybeUninit<&u32> = MaybeUninit::uninit();
const D2: Struct = Struct { a: 1, b: 2, c: 3, d: 4 };

const fn dangling<T>() -> *const T {
ptr::NonNull::dangling().as_ptr() as _
}

#[repr(C)]
struct Struct {
a: u8,
// _pad: [MaybeUninit<u8>; 3]
b: u32,
c: u16,
d: u8,
// _pad: [MaybeUninit<u8>; 1]
}

fn main() {}
Loading

0 comments on commit 0a43923

Please sign in to comment.