Skip to content

Commit 5498367

Browse files
authored
Rollup merge of rust-lang#75392 - TimDiekmann:non-null-uninit-slice, r=RalfJung
Add `as_uninit`-like methods to pointer types and unify documentation of `as_ref` methods This adds a convenient method to retrieve a `&(mut) [MaybeUninit<T>]` from slice pointers (`*const [T]`, `*mut [T]`, `NonNull<[T]>`). See also rust-lang/wg-allocators#66 (comment). ~I'll add a tracking issue as soon as it's reviewed and CI passed.~ Tracking Issue: rust-lang#75402 r? @RalfJung
2 parents 381a841 + 93e074b commit 5498367

File tree

4 files changed

+568
-81
lines changed

4 files changed

+568
-81
lines changed

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
#![feature(optin_builtin_traits)]
115115
#![feature(or_patterns)]
116116
#![feature(prelude_import)]
117+
#![feature(ptr_as_uninit)]
117118
#![feature(repr_simd, platform_intrinsics)]
118119
#![feature(rustc_attrs)]
119120
#![feature(simd_ffi)]

library/core/src/ptr/const_ptr.rs

+117-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::*;
22
use crate::cmp::Ordering::{self, Equal, Greater, Less};
33
use crate::intrinsics;
44
use crate::mem;
5-
use crate::slice::SliceIndex;
5+
use crate::slice::{self, SliceIndex};
66

77
#[lang = "const_ptr"]
88
impl<T: ?Sized> *const T {
@@ -48,32 +48,33 @@ impl<T: ?Sized> *const T {
4848
self as _
4949
}
5050

51-
/// Returns `None` if the pointer is null, or else returns a reference to
52-
/// the value wrapped in `Some`.
51+
/// Returns `None` if the pointer is null, or else returns a shared reference to
52+
/// the value wrapped in `Some`. If the value may be uninitialized, [`as_uninit_ref`]
53+
/// must be used instead.
5354
///
54-
/// # Safety
55+
/// [`as_uninit_ref`]: #method.as_uninit_ref
5556
///
56-
/// While this method and its mutable counterpart are useful for
57-
/// null-safety, it is important to note that this is still an unsafe
58-
/// operation because the returned value could be pointing to invalid
59-
/// memory.
57+
/// # Safety
6058
///
6159
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
6260
/// all of the following is true:
63-
/// - it is properly aligned
64-
/// - it must point to an initialized instance of T; in particular, the pointer must be
65-
/// "dereferenceable" in the sense defined [here].
61+
///
62+
/// * The pointer must be properly aligned.
63+
///
64+
/// * It must be "dereferencable" in the sense defined in [the module documentation].
65+
///
66+
/// * The pointer must point to an initialized instance of `T`.
67+
///
68+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
69+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
70+
/// In particular, for the duration of this lifetime, the memory the pointer points to must
71+
/// not get mutated (except inside `UnsafeCell`).
6672
///
6773
/// This applies even if the result of this method is unused!
6874
/// (The part about being initialized is not yet fully decided, but until
6975
/// it is, the only safe approach is to ensure that they are indeed initialized.)
7076
///
71-
/// Additionally, the lifetime `'a` returned is arbitrarily chosen and does
72-
/// not necessarily reflect the actual lifetime of the data. *You* must enforce
73-
/// Rust's aliasing rules. In particular, for the duration of this lifetime,
74-
/// the memory the pointer points to must not get mutated (except inside `UnsafeCell`).
75-
///
76-
/// [here]: crate::ptr#safety
77+
/// [the module documentation]: crate::ptr#safety
7778
///
7879
/// # Examples
7980
///
@@ -111,6 +112,56 @@ impl<T: ?Sized> *const T {
111112
if self.is_null() { None } else { unsafe { Some(&*self) } }
112113
}
113114

115+
/// Returns `None` if the pointer is null, or else returns a shared reference to
116+
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
117+
/// that the value has to be initialized.
118+
///
119+
/// [`as_ref`]: #method.as_ref
120+
///
121+
/// # Safety
122+
///
123+
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
124+
/// all of the following is true:
125+
///
126+
/// * The pointer must be properly aligned.
127+
///
128+
/// * It must be "dereferencable" in the sense defined in [the module documentation].
129+
///
130+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
131+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
132+
/// In particular, for the duration of this lifetime, the memory the pointer points to must
133+
/// not get mutated (except inside `UnsafeCell`).
134+
///
135+
/// This applies even if the result of this method is unused!
136+
///
137+
/// [the module documentation]: crate::ptr#safety
138+
///
139+
/// # Examples
140+
///
141+
/// Basic usage:
142+
///
143+
/// ```
144+
/// #![feature(ptr_as_uninit)]
145+
///
146+
/// let ptr: *const u8 = &10u8 as *const u8;
147+
///
148+
/// unsafe {
149+
/// if let Some(val_back) = ptr.as_uninit_ref() {
150+
/// println!("We got back the value: {}!", val_back.assume_init());
151+
/// }
152+
/// }
153+
/// ```
154+
#[inline]
155+
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
156+
pub unsafe fn as_uninit_ref<'a>(self) -> Option<&'a MaybeUninit<T>>
157+
where
158+
T: Sized,
159+
{
160+
// SAFETY: the caller must guarantee that `self` meets all the
161+
// requirements for a reference.
162+
if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit<T>) }) }
163+
}
164+
114165
/// Calculates the offset from a pointer.
115166
///
116167
/// `count` is in units of T; e.g., a `count` of 3 represents a pointer
@@ -925,6 +976,55 @@ impl<T> *const [T] {
925976
// SAFETY: the caller ensures that `self` is dereferencable and `index` in-bounds.
926977
unsafe { index.get_unchecked(self) }
927978
}
979+
980+
/// Returns `None` if the pointer is null, or else returns a shared slice to
981+
/// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
982+
/// that the value has to be initialized.
983+
///
984+
/// [`as_ref`]: #method.as_ref
985+
///
986+
/// # Safety
987+
///
988+
/// When calling this method, you have to ensure that *either* the pointer is NULL *or*
989+
/// all of the following is true:
990+
///
991+
/// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::<T>()` many bytes,
992+
/// and it must be properly aligned. This means in particular:
993+
///
994+
/// * The entire memory range of this slice must be contained within a single allocated object!
995+
/// Slices can never span across multiple allocated objects.
996+
///
997+
/// * The pointer must be aligned even for zero-length slices. One
998+
/// reason for this is that enum layout optimizations may rely on references
999+
/// (including slices of any length) being aligned and non-null to distinguish
1000+
/// them from other data. You can obtain a pointer that is usable as `data`
1001+
/// for zero-length slices using [`NonNull::dangling()`].
1002+
///
1003+
/// * The total size `ptr.len() * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
1004+
/// See the safety documentation of [`pointer::offset`].
1005+
///
1006+
/// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
1007+
/// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
1008+
/// In particular, for the duration of this lifetime, the memory the pointer points to must
1009+
/// not get mutated (except inside `UnsafeCell`).
1010+
///
1011+
/// This applies even if the result of this method is unused!
1012+
///
1013+
/// See also [`slice::from_raw_parts`][].
1014+
///
1015+
/// [valid]: crate::ptr#safety
1016+
/// [`NonNull::dangling()`]: NonNull::dangling
1017+
/// [`pointer::offset`]: ../std/primitive.pointer.html#method.offset
1018+
#[inline]
1019+
#[unstable(feature = "ptr_as_uninit", issue = "75402")]
1020+
pub unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
1021+
if self.is_null() {
1022+
None
1023+
} else {
1024+
// SAFETY: the caller must uphold the safety contract for `as_uninit_slice`.
1025+
Some(unsafe { slice::from_raw_parts(self as *const MaybeUninit<T>, self.len()) })
1026+
}
1027+
}
9281028
}
9291029

9301030
// Equality for pointers

0 commit comments

Comments
 (0)